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

Commit 8650c329 authored by Alex Sakhartchouk's avatar Alex Sakhartchouk
Browse files

Adding ability to read back fbo data to renderscript

Change-Id: Ie684c26cbcde22f2483b43415dfc39a3de22c5a1
parent f71e5469
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