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 android::renderscript::Context;
27 
RsdFrameBufferObj()28 RsdFrameBufferObj::RsdFrameBufferObj() {
29     mFBOId = 0;
30     mWidth = 0;
31     mHeight = 0;
32     mColorTargetsCount = 1;
33     mColorTargets = new DrvAllocation*[mColorTargetsCount];
34     for (uint32_t i = 0; i < mColorTargetsCount; i ++) {
35         mColorTargets[i] = 0;
36     }
37     mDepthTarget = nullptr;
38     mDirty = true;
39 }
40 
~RsdFrameBufferObj()41 RsdFrameBufferObj::~RsdFrameBufferObj() {
42     if(mFBOId != 0) {
43         glDeleteFramebuffers(1, &mFBOId);
44     }
45     delete [] mColorTargets;
46 }
47 
checkError(const Context * rsc)48 void RsdFrameBufferObj::checkError(const Context *rsc) {
49     GLenum status;
50     status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
51     switch (status) {
52     case GL_FRAMEBUFFER_COMPLETE:
53         break;
54     case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
55         rsc->setError(RS_ERROR_BAD_VALUE,
56                       "Unable to set up render Target: RFRAMEBUFFER_INCOMPLETE_ATTACHMENT");
57         break;
58     case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
59         rsc->setError(RS_ERROR_BAD_VALUE,
60                       "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
61         break;
62     case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
63         rsc->setError(RS_ERROR_BAD_VALUE,
64                       "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
65         break;
66     case GL_FRAMEBUFFER_UNSUPPORTED:
67         rsc->setError(RS_ERROR_BAD_VALUE,
68                       "Unable to set up render Target: GL_FRAMEBUFFER_UNSUPPORTED");
69         break;
70     }
71 }
72 
73 
setDepthAttachment()74 void RsdFrameBufferObj::setDepthAttachment() {
75     if (mDepthTarget != nullptr) {
76         if (mDepthTarget->textureID) {
77             glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
78                                    GL_TEXTURE_2D, mDepthTarget->textureID, 0);
79         } else {
80             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
81                                       GL_RENDERBUFFER, mDepthTarget->renderTargetID);
82         }
83     } else {
84         // Reset last attachment
85         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
86         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
87     }
88 }
89 
setColorAttachment()90 void RsdFrameBufferObj::setColorAttachment() {
91     // Now attach color targets
92     for (uint32_t i = 0; i < mColorTargetsCount; i ++) {
93         if (mColorTargets[i] != nullptr) {
94             if (mColorTargets[i]->textureID) {
95                 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
96                                        GL_TEXTURE_2D, mColorTargets[i]->textureID, 0);
97             } else {
98                 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
99                                           GL_RENDERBUFFER, mColorTargets[i]->renderTargetID);
100             }
101         } else {
102             // Reset last attachment
103             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
104                                       GL_RENDERBUFFER, 0);
105             glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
106                                    GL_TEXTURE_2D, 0, 0);
107         }
108     }
109 }
110 
renderToFramebuffer()111 bool RsdFrameBufferObj::renderToFramebuffer() {
112     if (mDepthTarget != nullptr) {
113         return false;
114     }
115 
116     for (uint32_t i = 0; i < mColorTargetsCount; i ++) {
117         if (mColorTargets[i] != nullptr) {
118             return false;
119         }
120     }
121     return true;
122 }
123 
setActive(const Context * rsc)124 void RsdFrameBufferObj::setActive(const Context *rsc) {
125     RsdHal *dc = (RsdHal *)rsc->mHal.drv;
126     bool framebuffer = renderToFramebuffer();
127 
128     if(mColorTargets[0] && mColorTargets[0]->wnd) {
129         rsdGLSetInternalSurface(rsc, mColorTargets[0]->wnd);
130         EGLint width, height;
131         eglQuerySurface(dc->gl.egl.display, dc->gl.egl.surface, EGL_WIDTH, &width);
132         eglQuerySurface(dc->gl.egl.display, dc->gl.egl.surface, EGL_HEIGHT, &height);
133         RSD_CALL_GL(glViewport, 0, 0, width, height);
134     } else {
135         if (!framebuffer) {
136             if(mFBOId == 0) {
137                 RSD_CALL_GL(glGenFramebuffers, 1, &mFBOId);
138             }
139             RSD_CALL_GL(glBindFramebuffer, GL_FRAMEBUFFER, mFBOId);
140 
141             if (mDirty) {
142                 setDepthAttachment();
143                 setColorAttachment();
144                 mDirty = false;
145             }
146 
147             RSD_CALL_GL(glViewport, 0, 0, mWidth, mHeight);
148             checkError(rsc);
149         } else {
150             if(dc->gl.wndSurface != dc->gl.currentWndSurface) {
151                 rsdGLSetInternalSurface(rsc, dc->gl.wndSurface);
152             } else {
153                 RSD_CALL_GL(glBindFramebuffer, GL_FRAMEBUFFER, 0);
154             }
155             RSD_CALL_GL(glViewport, 0, 0, rsc->getWidth(), rsc->getHeight());
156         }
157     }
158 }
159