Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9347d9ad authored by Alex Sakhartchouk's avatar Alex Sakhartchouk Committed by Android (Google) Code Review
Browse files

Merge "Adding ability to read back fbo data to renderscript"

parents 4bd44535 8650c329
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -119,6 +119,7 @@ LOCAL_SRC_FILES:= \
	driver/rsdBcc.cpp \
	driver/rsdCore.cpp \
	driver/rsdFrameBuffer.cpp \
	driver/rsdFrameBufferObj.cpp \
	driver/rsdGL.cpp \
	driver/rsdMesh.cpp \
	driver/rsdMeshObj.cpp \
+90 −2
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include "rsdBcc.h"
#include "rsdRuntime.h"
#include "rsdAllocation.h"
#include "rsdFrameBufferObj.h"

#include "rsAllocation.h"

@@ -244,6 +245,9 @@ bool rsdAllocationInit(const Context *rsc, Allocation *alloc, bool forceZero) {
    if (alloc->mHal.state.usageFlags & ~RS_ALLOCATION_USAGE_SCRIPT) {
        drv->uploadDeferred = true;
    }

    drv->readBackFBO = NULL;

    return true;
}

@@ -269,6 +273,10 @@ void rsdAllocationDestroy(const Context *rsc, Allocation *alloc) {
        free(drv->mallocPtr);
        drv->mallocPtr = NULL;
    }
    if (drv->readBackFBO != NULL) {
        delete drv->readBackFBO;
        drv->readBackFBO = NULL;
    }
    free(drv);
    alloc->mHal.drv = NULL;
}
@@ -292,13 +300,52 @@ void rsdAllocationResize(const Context *rsc, const Allocation *alloc,
    }
}

static void rsdAllocationSyncFromFBO(const Context *rsc, const Allocation *alloc) {
    if (!alloc->getIsScript()) {
        return; // nothing to sync
    }

    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
    RsdFrameBufferObj *lastFbo = dc->gl.currentFrameBuffer;

    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
    if (!drv->textureID && !drv->renderTargetID) {
        return; // nothing was rendered here yet, so nothing to sync
    }
    if (drv->readBackFBO == NULL) {
        drv->readBackFBO = new RsdFrameBufferObj();
        drv->readBackFBO->setColorTarget(drv, 0);
        drv->readBackFBO->setDimensions(alloc->getType()->getDimX(),
                                        alloc->getType()->getDimY());
    }

    // Bind the framebuffer object so we can read back from it
    drv->readBackFBO->setActive(rsc);

    // Do the readback
    glReadPixels(0, 0, alloc->getType()->getDimX(), alloc->getType()->getDimY(),
                 drv->glFormat, drv->glType, alloc->getPtr());

    // Revert framebuffer to its original
    lastFbo->setActive(rsc);
}


void rsdAllocationSyncAll(const Context *rsc, const Allocation *alloc,
                         RsAllocationUsageType src) {
    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;

    if (!drv->uploadDeferred) {
    if (src == RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
        if(!alloc->getIsRenderTarget()) {
            rsc->setError(RS_ERROR_FATAL_DRIVER,
                          "Attempting to sync allocation from render target, "
                          "for non-render target allocation");
        } else if (alloc->getType()->getElement()->getKind() != RS_KIND_PIXEL_RGBA) {
            rsc->setError(RS_ERROR_FATAL_DRIVER, "Cannot only sync from RGBA"
                                                 "render target");
        } else {
            rsdAllocationSyncFromFBO(rsc, alloc);
        }
        return;
    }

@@ -385,6 +432,39 @@ void rsdAllocationData1D_alloc(const android::renderscript::Context *rsc,
                               uint32_t srcXoff, uint32_t srcLod) {
}

uint8_t *getOffsetPtr(const android::renderscript::Allocation *alloc,
                      uint32_t xoff, uint32_t yoff, uint32_t lod,
                      RsAllocationCubemapFace face) {
    uint8_t *ptr = static_cast<uint8_t *>(alloc->getPtr());
    ptr += alloc->getType()->getLODOffset(lod, xoff, yoff);

    if (face != 0) {
        uint32_t totalSizeBytes = alloc->getType()->getSizeBytes();
        uint32_t faceOffset = totalSizeBytes / 6;
        ptr += faceOffset * (uint32_t)face;
    }
    return ptr;
}


void rsdAllocationData2D_alloc_script(const android::renderscript::Context *rsc,
                                      const android::renderscript::Allocation *dstAlloc,
                                      uint32_t dstXoff, uint32_t dstYoff, uint32_t dstLod,
                                      RsAllocationCubemapFace dstFace, uint32_t w, uint32_t h,
                                      const android::renderscript::Allocation *srcAlloc,
                                      uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod,
                                      RsAllocationCubemapFace srcFace) {
    uint32_t elementSize = dstAlloc->getType()->getElementSizeBytes();
    for (uint32_t i = 0; i < h; i ++) {
        uint8_t *dstPtr = getOffsetPtr(dstAlloc, dstXoff, dstYoff + i, dstLod, dstFace);
        uint8_t *srcPtr = getOffsetPtr(srcAlloc, srcXoff, srcYoff + i, srcLod, srcFace);
        memcpy(dstPtr, srcPtr, w * elementSize);

        LOGE("COPIED dstXoff(%u), dstYoff(%u), dstLod(%u), dstFace(%u), w(%u), h(%u), srcXoff(%u), srcYoff(%u), srcLod(%u), srcFace(%u)",
             dstXoff, dstYoff, dstLod, dstFace, w, h, srcXoff, srcYoff, srcLod, srcFace);
    }
}

void rsdAllocationData2D_alloc(const android::renderscript::Context *rsc,
                               const android::renderscript::Allocation *dstAlloc,
                               uint32_t dstXoff, uint32_t dstYoff, uint32_t dstLod,
@@ -392,6 +472,14 @@ void rsdAllocationData2D_alloc(const android::renderscript::Context *rsc,
                               const android::renderscript::Allocation *srcAlloc,
                               uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod,
                               RsAllocationCubemapFace srcFace) {
    if (!dstAlloc->getIsScript() && !srcAlloc->getIsScript()) {
        rsc->setError(RS_ERROR_FATAL_DRIVER, "Non-script allocation copies not "
                                             "yet implemented.");
        return;
    }
    rsdAllocationData2D_alloc_script(rsc, dstAlloc, dstXoff, dstYoff,
                                     dstLod, dstFace, w, h, srcAlloc,
                                     srcXoff, srcYoff, srcLod, srcFace);
}

void rsdAllocationData3D_alloc(const android::renderscript::Context *rsc,
+4 −1
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@
#include <GLES/gl.h>
#include <GLES2/gl2.h>

class RsdFrameBufferObj;

struct DrvAllocation {
    // Is this a legal structure to be used as a texture source.
    // Initially this will require 1D or 2D and color data
@@ -42,8 +44,9 @@ struct DrvAllocation {
    GLenum glType;
    GLenum glFormat;


    bool uploadDeferred;

    RsdFrameBufferObj * readBackFBO;
};

GLenum rsdTypeToGLType(RsDataType t);
+38 −100
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@

#include "rsdCore.h"
#include "rsdFrameBuffer.h"
#include "rsdFrameBufferObj.h"
#include "rsdAllocation.h"

#include "rsContext.h"
@@ -28,133 +29,70 @@
using namespace android;
using namespace android::renderscript;

struct DrvFrameBuffer {
    GLuint mFBOId;
};

void checkError(const Context *rsc) {
    GLenum status;
    status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    switch (status) {
    case GL_FRAMEBUFFER_COMPLETE:
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
        rsc->setError(RS_ERROR_BAD_VALUE,
                      "Unable to set up render Target: RFRAMEBUFFER_INCOMPLETE_ATTACHMENT");
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
        rsc->setError(RS_ERROR_BAD_VALUE,
                      "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
        rsc->setError(RS_ERROR_BAD_VALUE,
                      "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
        break;
    case GL_FRAMEBUFFER_UNSUPPORTED:
        rsc->setError(RS_ERROR_BAD_VALUE,
                      "Unable to set up render Target: GL_FRAMEBUFFER_UNSUPPORTED");
        break;
    }
}


void setDepthAttachment(const Context *rsc, const FBOCache *fb) {
    RsdFrameBufferObj *fbo = (RsdFrameBufferObj*)fb->mHal.drv;

    DrvAllocation *depth = NULL;
    if (fb->mHal.state.depthTarget.get() != NULL) {
        DrvAllocation *drv = (DrvAllocation *)fb->mHal.state.depthTarget->mHal.drv;

        if (drv->textureID) {
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                                   GL_TEXTURE_2D, drv->textureID, 0);
        } else {
            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                                      GL_RENDERBUFFER, drv->renderTargetID);
        depth = (DrvAllocation *)fb->mHal.state.depthTarget->mHal.drv;

        if (depth->uploadDeferred) {
            rsdAllocationSyncAll(rsc, fb->mHal.state.depthTarget.get(),
                                 RS_ALLOCATION_USAGE_SCRIPT);
        }
    } else {
        // Reset last attachment
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
    }
    fbo->setDepthTarget(depth);
}

void setColorAttachment(const Context *rsc, const FBOCache *fb) {
    RsdFrameBufferObj *fbo = (RsdFrameBufferObj*)fb->mHal.drv;
    // Now attach color targets
    for (uint32_t i = 0; i < fb->mHal.state.colorTargetsCount; i ++) {
        uint32_t texID = 0;
        DrvAllocation *color = NULL;
        if (fb->mHal.state.colorTargets[i].get() != NULL) {
            DrvAllocation *drv = (DrvAllocation *)fb->mHal.state.colorTargets[i]->mHal.drv;

            if (drv->textureID) {
                glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
                                       GL_TEXTURE_2D, drv->textureID, 0);
            } else {
                glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
                                          GL_RENDERBUFFER, drv->renderTargetID);
            }
        } else {
            // Reset last attachment
            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
                                      GL_RENDERBUFFER, 0);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
                                   GL_TEXTURE_2D, 0, 0);
        }
    }
}
            color = (DrvAllocation *)fb->mHal.state.colorTargets[i]->mHal.drv;

bool renderToFramebuffer(const FBOCache *fb) {
    if (fb->mHal.state.depthTarget.get() != NULL) {
        return false;
            if (color->uploadDeferred) {
                rsdAllocationSyncAll(rsc, fb->mHal.state.colorTargets[i].get(),
                                     RS_ALLOCATION_USAGE_SCRIPT);
            }

    for (uint32_t i = 0; i < fb->mHal.state.colorTargetsCount; i ++) {
        if (fb->mHal.state.colorTargets[i].get() != NULL) {
            return false;
        }
        fbo->setColorTarget(color, i);
    }
    return true;
}


bool rsdFrameBufferInit(const Context *rsc, const FBOCache *fb) {
    DrvFrameBuffer *drv = (DrvFrameBuffer *)calloc(1, sizeof(DrvFrameBuffer));
    if (drv == NULL) {
    RsdFrameBufferObj *fbo = new RsdFrameBufferObj();
    if (fbo == NULL) {
        return false;
    }
    fb->mHal.drv = drv;
    drv->mFBOId = 0;
    fb->mHal.drv = fbo;

    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
    dc->gl.currentFrameBuffer = fbo;

    return true;
}

void rsdFrameBufferSetActive(const Context *rsc, const FBOCache *fb) {
    DrvFrameBuffer *drv = (DrvFrameBuffer *)fb->mHal.drv;

    bool framebuffer = renderToFramebuffer(fb);
    if (!framebuffer) {
        if(drv->mFBOId == 0) {
            glGenFramebuffers(1, &drv->mFBOId);
        }
        glBindFramebuffer(GL_FRAMEBUFFER, drv->mFBOId);

    setDepthAttachment(rsc, fb);
    setColorAttachment(rsc, fb);

        glViewport(0, 0, fb->mHal.state.colorTargets[0]->getType()->getDimX(),
    RsdFrameBufferObj *fbo = (RsdFrameBufferObj *)fb->mHal.drv;
    if (fb->mHal.state.colorTargets[0].get()) {
        fbo->setDimensions(fb->mHal.state.colorTargets[0]->getType()->getDimX(),
                           fb->mHal.state.colorTargets[0]->getType()->getDimY());

        checkError(rsc);
    } else {
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glViewport(0, 0, rsc->getWidth(), rsc->getHeight());
    }
    } else if (fb->mHal.state.depthTarget.get()) {
        fbo->setDimensions(fb->mHal.state.depthTarget->getType()->getDimX(),
                           fb->mHal.state.depthTarget->getType()->getDimY());
    }

void rsdFrameBufferDestroy(const Context *rsc, const FBOCache *fb) {
    DrvFrameBuffer *drv = (DrvFrameBuffer *)fb->mHal.drv;
    if(drv->mFBOId != 0) {
        glDeleteFramebuffers(1, &drv->mFBOId);
    fbo->setActive(rsc);
}

    free(fb->mHal.drv);
void rsdFrameBufferDestroy(const Context *rsc, const FBOCache *fb) {
    RsdFrameBufferObj *fbo = (RsdFrameBufferObj *)fb->mHal.drv;
    delete fbo;
    fb->mHal.drv = NULL;
}

+143 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "rsdFrameBufferObj.h"
#include "rsdAllocation.h"

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

using namespace android;
using namespace android::renderscript;

RsdFrameBufferObj::RsdFrameBufferObj() {
    mFBOId = 0;
    mWidth = 0;
    mHeight = 0;
    mColorTargetsCount = 1;
    mColorTargets = new DrvAllocation*[mColorTargetsCount];
    for (uint32_t i = 0; i < mColorTargetsCount; i ++) {
        mColorTargets[i] = 0;
    }
    mDepthTarget = NULL;
    mDirty = true;
}

RsdFrameBufferObj::~RsdFrameBufferObj() {
    if(mFBOId != 0) {
        glDeleteFramebuffers(1, &mFBOId);
    }
    delete [] mColorTargets;
}

void RsdFrameBufferObj::checkError(const Context *rsc) {
    GLenum status;
    status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    switch (status) {
    case GL_FRAMEBUFFER_COMPLETE:
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
        rsc->setError(RS_ERROR_BAD_VALUE,
                      "Unable to set up render Target: RFRAMEBUFFER_INCOMPLETE_ATTACHMENT");
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
        rsc->setError(RS_ERROR_BAD_VALUE,
                      "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
        rsc->setError(RS_ERROR_BAD_VALUE,
                      "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
        break;
    case GL_FRAMEBUFFER_UNSUPPORTED:
        rsc->setError(RS_ERROR_BAD_VALUE,
                      "Unable to set up render Target: GL_FRAMEBUFFER_UNSUPPORTED");
        break;
    }
}


void RsdFrameBufferObj::setDepthAttachment() {
    if (mDepthTarget != NULL) {
        if (mDepthTarget->textureID) {
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                                   GL_TEXTURE_2D, mDepthTarget->textureID, 0);
        } else {
            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                                      GL_RENDERBUFFER, mDepthTarget->renderTargetID);
        }
    } else {
        // Reset last attachment
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
    }
}

void RsdFrameBufferObj::setColorAttachment() {
    // Now attach color targets
    for (uint32_t i = 0; i < mColorTargetsCount; i ++) {
        if (mColorTargets[i] != NULL) {
            if (mColorTargets[i]->textureID) {
                glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
                                       GL_TEXTURE_2D, mColorTargets[i]->textureID, 0);
            } else {
                glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
                                          GL_RENDERBUFFER, mColorTargets[i]->renderTargetID);
            }
        } else {
            // Reset last attachment
            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
                                      GL_RENDERBUFFER, 0);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
                                   GL_TEXTURE_2D, 0, 0);
        }
    }
}

bool RsdFrameBufferObj::renderToFramebuffer() {
    if (mDepthTarget != NULL) {
        return false;
    }

    for (uint32_t i = 0; i < mColorTargetsCount; i ++) {
        if (mColorTargets[i] != NULL) {
            return false;
        }
    }
    return true;
}

void RsdFrameBufferObj::setActive(const Context *rsc) {
    bool framebuffer = renderToFramebuffer();
    if (!framebuffer) {
        if(mFBOId == 0) {
            glGenFramebuffers(1, &mFBOId);
        }
        glBindFramebuffer(GL_FRAMEBUFFER, mFBOId);

        if (mDirty) {
            setDepthAttachment();
            setColorAttachment();
            mDirty = false;
        }

        glViewport(0, 0, mWidth, mHeight);
        checkError(rsc);
    } else {
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glViewport(0, 0, rsc->getWidth(), rsc->getHeight());
    }
}
Loading