1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 
18 #include "rsdFrameBufferObj.h"
19 #include "rsdAllocation.h"
20 #include "rsdGL.h"
21 #include "rsdCore.h"
22 
23 #include <GLES2/gl2.h>
24 #include <GLES2/gl2ext.h>
25 
26 using namespace android;
27 using namespace android::renderscript;
28 
RsdFrameBufferObj()29 RsdFrameBufferObj::RsdFrameBufferObj() {
30     mFBOId = 0;
31     mWidth = 0;
32     mHeight = 0;
33     mColorTargetsCount = 1;
34     mColorTargets = new DrvAllocation*[mColorTargetsCount];
35     for (uint32_t i = 0; i < mColorTargetsCount; i ++) {
36         mColorTargets[i] = 0;
37     }
38     mDepthTarget = nullptr;
39     mDirty = true;
40 }
41 
~RsdFrameBufferObj()42 RsdFrameBufferObj::~RsdFrameBufferObj() {
43     if(mFBOId != 0) {
44         glDeleteFramebuffers(1, &mFBOId);
45     }
46     delete [] mColorTargets;
47 }
48 
checkError(const Context * rsc)49 void RsdFrameBufferObj::checkError(const Context *rsc) {
50     GLenum status;
51     status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
52     switch (status) {
53     case GL_FRAMEBUFFER_COMPLETE:
54         break;
55     case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
56         rsc->setError(RS_ERROR_BAD_VALUE,
57                       "Unable to set up render Target: RFRAMEBUFFER_INCOMPLETE_ATTACHMENT");
58         break;
59     case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
60         rsc->setError(RS_ERROR_BAD_VALUE,
61                       "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
62         break;
63     case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
64         rsc->setError(RS_ERROR_BAD_VALUE,
65                       "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
66         break;
67     case GL_FRAMEBUFFER_UNSUPPORTED:
68         rsc->setError(RS_ERROR_BAD_VALUE,
69                       "Unable to set up render Target: GL_FRAMEBUFFER_UNSUPPORTED");
70         break;
71     }
72 }
73 
74 
setDepthAttachment()75 void RsdFrameBufferObj::setDepthAttachment() {
76     if (mDepthTarget != nullptr) {
77         if (mDepthTarget->textureID) {
78             glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
79                                    GL_TEXTURE_2D, mDepthTarget->textureID, 0);
80         } else {
81             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
82                                       GL_RENDERBUFFER, mDepthTarget->renderTargetID);
83         }
84     } else {
85         // Reset last attachment
86         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
87         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
88     }
89 }
90 
setColorAttachment()91 void RsdFrameBufferObj::setColorAttachment() {
92     // Now attach color targets
93     for (uint32_t i = 0; i < mColorTargetsCount; i ++) {
94         if (mColorTargets[i] != nullptr) {
95             if (mColorTargets[i]->textureID) {
96                 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
97                                        GL_TEXTURE_2D, mColorTargets[i]->textureID, 0);
98             } else {
99                 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
100                                           GL_RENDERBUFFER, mColorTargets[i]->renderTargetID);
101             }
102         } else {
103             // Reset last attachment
104             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
105                                       GL_RENDERBUFFER, 0);
106             glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
107                                    GL_TEXTURE_2D, 0, 0);
108         }
109     }
110 }
111 
renderToFramebuffer()112 bool RsdFrameBufferObj::renderToFramebuffer() {
113     if (mDepthTarget != nullptr) {
114         return false;
115     }
116 
117     for (uint32_t i = 0; i < mColorTargetsCount; i ++) {
118         if (mColorTargets[i] != nullptr) {
119             return false;
120         }
121     }
122     return true;
123 }
124 
setActive(const Context * rsc)125 void RsdFrameBufferObj::setActive(const Context *rsc) {
126     RsdHal *dc = (RsdHal *)rsc->mHal.drv;
127     bool framebuffer = renderToFramebuffer();
128 
129     if(mColorTargets[0] && mColorTargets[0]->wnd) {
130         rsdGLSetInternalSurface(rsc, mColorTargets[0]->wnd);
131         EGLint width, height;
132         eglQuerySurface(dc->gl.egl.display, dc->gl.egl.surface, EGL_WIDTH, &width);
133         eglQuerySurface(dc->gl.egl.display, dc->gl.egl.surface, EGL_HEIGHT, &height);
134         RSD_CALL_GL(glViewport, 0, 0, width, height);
135     } else {
136         if (!framebuffer) {
137             if(mFBOId == 0) {
138                 RSD_CALL_GL(glGenFramebuffers, 1, &mFBOId);
139             }
140             RSD_CALL_GL(glBindFramebuffer, GL_FRAMEBUFFER, mFBOId);
141 
142             if (mDirty) {
143                 setDepthAttachment();
144                 setColorAttachment();
145                 mDirty = false;
146             }
147 
148             RSD_CALL_GL(glViewport, 0, 0, mWidth, mHeight);
149             checkError(rsc);
150         } else {
151             if(dc->gl.wndSurface != dc->gl.currentWndSurface) {
152                 rsdGLSetInternalSurface(rsc, dc->gl.wndSurface);
153             } else {
154                 RSD_CALL_GL(glBindFramebuffer, GL_FRAMEBUFFER, 0);
155             }
156             RSD_CALL_GL(glViewport, 0, 0, rsc->getWidth(), rsc->getHeight());
157         }
158     }
159 }
160