All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.prism.es2.ES2RTTexture Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.prism.es2;

import com.sun.glass.ui.Screen;
import com.sun.prism.Graphics;
import com.sun.prism.Image;
import com.sun.prism.PixelFormat;
import com.sun.prism.RTTexture;
import com.sun.prism.ReadbackRenderTarget;
import com.sun.prism.Texture;
import com.sun.prism.impl.PrismSettings;

import java.nio.Buffer;

class ES2RTTexture extends ES2Texture
        implements ES2RenderTarget, RTTexture, ReadbackRenderTarget
{

    private boolean opaque;

    private ES2RTTexture(ES2Context context, ES2TextureResource resource,
                         WrapMode wrapMode,
                         int physicalWidth, int physicalHeight,
                         int contentX, int contentY,
                         int contentWidth, int contentHeight)
    {
        super(context, resource, PixelFormat.BYTE_BGRA_PRE, wrapMode,
                physicalWidth, physicalHeight,
                contentX, contentY,
                contentWidth, contentHeight);
        this.opaque = false;
    }

    /**
     * Attach a depth buffer to the currently bound FBO
     * @param context current context
     */
    void attachDepthBuffer(ES2Context context) {
        // Return immediately if this RTT already has a depth buffer
        ES2RTTextureData texData = resource.getResource();
        int dbID = texData.getDepthBufferID();
        if (dbID != 0) {
            return;
        }
        dbID = context.getGLContext().createDepthBuffer(getPhysicalWidth(),
                getPhysicalHeight());

        // Add to disposer record so that we can cleanup the depth buffer when
        // this RTT is destroyed.
        texData.setDepthBufferID(dbID);
    }

    static int getCompatibleDimension(ES2Context context, int dim, WrapMode wrapMode) {
        GLContext glContext = context.getGLContext();
        boolean pad;
        switch (wrapMode) {
            case CLAMP_NOT_NEEDED:
                pad = false;
                break;
            case CLAMP_TO_ZERO:
                pad = !glContext.canClampToZero();
                break;
            default:
            case CLAMP_TO_EDGE:
            case REPEAT:
                throw new IllegalArgumentException("wrap mode not supported for RT textures: "+wrapMode);
            case CLAMP_TO_EDGE_SIMULATED:
            case CLAMP_TO_ZERO_SIMULATED:
            case REPEAT_SIMULATED:
                throw new IllegalArgumentException("Cannot request simulated wrap mode: "+wrapMode);
        }

        int paddedDim = pad ? dim + 2 : dim;

        int maxSize = glContext.getMaxTextureSize();
        int texDim;
        if (glContext.canCreateNonPowTwoTextures()) {
            texDim = (paddedDim <= maxSize) ? paddedDim : 0;
        } else {
            texDim = nextPowerOfTwo(paddedDim, maxSize);
        }

        if (texDim == 0) {
            throw new RuntimeException(
                    "Requested texture dimension (" + dim + ") "
                    + "requires dimension (" + texDim + ") "
                    + "that exceeds maximum texture size (" + maxSize + ")");
        }

        // make sure the texture is not smaller than minimum size
        texDim = Math.max(texDim, PrismSettings.minRTTSize);

        // Note that ES2Context will set the viewport to the content
        // region of a RenderTarget (to ensure that we don't render into
        // the padded area of transparent pixels, if present).  Since
        // RTTextures are frequently recycled (i.e., reused by Decora) it
        // is imperative that we initialize the content region of the
        // RTTexture to be the physical size of the FBO modulo the padded
        // region.  (Suppose the caller asks for a 110x220 RTTexture, but
        // nonpow2 textures aren't supported; in this case, we will actually
        // create a 128x256 FBO.  If later that RTTexture gets reused for
        // a caller expecting to use 126x240 pixels, the viewport will be
        // setup correctly because it will set to the content region, or
        // 128x256 in this case, assuming no padding.)
        return pad ? texDim - 2 : texDim;
    }

    static ES2RTTexture create(ES2Context context, int w, int h, WrapMode wrapMode) {
        // Normally we would use GL_CLAMP_TO_BORDER with a transparent border
        // color to implement our CLAMP_TO_ZERO edge mode, but unfortunately
        // that mode is not available in OpenGL ES.  The workaround is to pad
        // the fbo with 1 row/column of transparent pixels on each side if the
        // caller requires and requests it, and we have to be careful to use
        // the getContentX/Y/Width/Height() methods so that we access only the
        // content area of the texture.
        // The downside of this approach is that when npot textures are not
        // supported, the padding may cause us to cross the power-of-two
        // threshold more easily and therefore waste more VRAM.
        // Note that only CLAMP_NOT_NEEDED and CLAMP_TO_ZERO are supported
        // for RT textures.  The other modes could be supported on desktop
        // platforms, but emulating them on non-GL2 platforms would be
        // prohibitively difficult.

        GLContext glContext = context.getGLContext();
        boolean pad;
        switch (wrapMode) {
            case CLAMP_NOT_NEEDED:
                pad = false;
                break;
            case CLAMP_TO_ZERO:
                pad = !glContext.canClampToZero();
                break;
            default:
            case CLAMP_TO_EDGE:
            case REPEAT:
                throw new IllegalArgumentException("wrap mode not supported for RT textures: "+wrapMode);
            case CLAMP_TO_EDGE_SIMULATED:
            case CLAMP_TO_ZERO_SIMULATED:
            case REPEAT_SIMULATED:
                throw new IllegalArgumentException("Cannot request simulated wrap mode: "+wrapMode);
        }

        int contentX, contentY;
        int paddedW, paddedH;
        if (pad) {
            contentX = 1;
            contentY = 1;
            paddedW = w + 2;
            paddedH = h + 2;
            wrapMode = wrapMode.simulatedVersion();
        } else {
            contentX = 0;
            contentY = 0;
            paddedW = w;
            paddedH = h;
        }

        int maxSize = glContext.getMaxTextureSize();
        int texWidth, texHeight;
        if (glContext.canCreateNonPowTwoTextures()) {
            texWidth = (paddedW <= maxSize) ? paddedW : 0;
            texHeight = (paddedH <= maxSize) ? paddedH : 0;
        } else {
            texWidth = nextPowerOfTwo(paddedW, maxSize);
            texHeight = nextPowerOfTwo(paddedH, maxSize);
        }

        if (texWidth == 0 || texHeight == 0) {
            throw new RuntimeException(
                    "Requested texture dimensions (" + w + "x" + h + ") "
                    + "require dimensions (" + texWidth + "x" + texHeight + ") "
                    + "that exceed maximum texture size (" + maxSize + ")");
        }

        // make sure the texture is not smaller than minimum size
        int minSize = PrismSettings.minRTTSize;
        texWidth = Math.max(texWidth, minSize);
        texHeight = Math.max(texHeight, minSize);

        ES2VramPool pool = ES2VramPool.instance;
        long size = pool.estimateRTTextureSize(texWidth, texHeight, false);
        if (!pool.prepareForAllocation(size)) {
            return null;
        }

        // Note that ES2Context will set the viewport to the content
        // region of a RenderTarget (to ensure that we don't render into
        // the padded area of transparent pixels, if present).  Since
        // RTTextures are frequently recycled (i.e., reused by Decora) it
        // is imperative that we initialize the content region of the
        // RTTexture to be the physical size of the FBO modulo the padded
        // region.  (Suppose the caller asks for a 110x220 RTTexture, but
        // nonpow2 textures aren't supported; in this case, we will actually
        // create a 128x256 FBO.  If later that RTTexture gets reused for
        // a caller expecting to use 126x240 pixels, the viewport will be
        // setup correctly because it will set to the content region, or
        // 128x256 in this case, assuming no padding.)
        int contentW, contentH;

        if (pad) {
            contentW = texWidth - 2;
            contentH = texHeight - 2;
        } else {
            contentW = texWidth;
            contentH = texHeight;
        }

        // save current texture
        glContext.setActiveTextureUnit(0);
        int savedTex = glContext.getBoundTexture();

        int nativeTexID = glContext.createTexture(texWidth, texHeight);

        int nativeFBOID = 0;
        if (nativeTexID != 0) {
            // Create FBO (this method will save and restore the previous bound FBO)
            nativeFBOID = glContext.createFBO(nativeTexID, texWidth, texHeight);
            if (nativeFBOID == 0) {
                glContext.deleteTexture(nativeTexID);
                nativeTexID = 0;
            }
        }
        ES2RTTextureData texData =
            new ES2RTTextureData(context, nativeTexID, nativeFBOID, size);
        ES2TextureResource texRes =
            new ES2TextureResource(texData);

        // restore previous texture
        glContext.setBoundTexture(savedTex);

        return new ES2RTTexture(context, texRes, wrapMode,
                                texWidth, texHeight,
                                contentX, contentY,
                                contentW, contentH);
    }

    public Texture getBackBuffer() {
        return this;
    }

    public Graphics createGraphics() {
        return ES2Graphics.create(context, this);
    }

    public int[] getPixels() {
        return null;
    }

    public boolean readPixels(Buffer pixels, int x, int y, int width, int height) {
        context.flushVertexBuffer();
        GLContext glContext = context.getGLContext();
        return glContext.readPixels(pixels, x, y, width, height);
    }

    public boolean readPixels(Buffer pixels) {
        context.flushVertexBuffer();
        GLContext glContext = context.getGLContext();
        int id = glContext.getBoundFBO();
        int fboID = getFboID();
        boolean changeBoundFBO = id != fboID;
        if (changeBoundFBO) {
            glContext.bindFBO(fboID);
        }
        boolean result = glContext.readPixels(pixels, getContentX(), getContentY(),
                 getContentWidth(), getContentHeight());                
        if (changeBoundFBO) {
            glContext.bindFBO(id);
        }
        return result;
    }

    public int getFboID() {
        return resource.getResource().getFboID();
    }

    public Screen getAssociatedScreen() {
        return context.getAssociatedScreen();
    }

    @Override
    public void update(Image img) {
        throw new UnsupportedOperationException("update() not supported for RTTextures");
    }

    @Override
    public void update(Image img, int dstx, int dsty) {
        throw new UnsupportedOperationException("update() not supported for RTTextures");
    }

    @Override
    public void update(Image img, int dstx, int dsty, int w, int h) {
        throw new UnsupportedOperationException("update() not supported for RTTextures");
    }

    @Override
    public void update(Image img, int dstx, int dsty, int w, int h, boolean skipFlush) {
        throw new UnsupportedOperationException("update() not supported for RTTextures");
    }

    @Override
    public void update(Buffer pixels, PixelFormat format,
            int dstx, int dsty,
            int srcx, int srcy, int srcw, int srch, int srcscan,
            boolean skipFlush) {
        throw new UnsupportedOperationException("update() not supported for RTTextures");
    }

    public boolean isOpaque() {
        return opaque;
    }

    public void setOpaque(boolean opaque) {
        this.opaque = opaque;
    }

    public boolean isVolatile() {
        return false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy