1 /*
2  * Copyright (C) 2014 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 #include "renderstate/RenderState.h"
17 
18 #include "renderthread/CanvasContext.h"
19 #include "renderthread/EglManager.h"
20 #include "utils/GLUtils.h"
21 
22 namespace android {
23 namespace uirenderer {
24 
RenderState(renderthread::RenderThread & thread)25 RenderState::RenderState(renderthread::RenderThread& thread)
26         : mRenderThread(thread)
27         , mViewportWidth(0)
28         , mViewportHeight(0)
29         , mFramebuffer(0) {
30     mThreadId = pthread_self();
31 }
32 
~RenderState()33 RenderState::~RenderState() {
34     LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
35             "State object lifecycle not managed correctly");
36 }
37 
onGLContextCreated()38 void RenderState::onGLContextCreated() {
39     LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
40             "State object lifecycle not managed correctly");
41     mBlend = new Blend();
42     mMeshState = new MeshState();
43     mScissor = new Scissor();
44     mStencil = new Stencil();
45 
46     // This is delayed because the first access of Caches makes GL calls
47     if (!mCaches) {
48         mCaches = &Caches::createInstance(*this);
49     }
50     mCaches->init();
51     mCaches->textureCache.setAssetAtlas(&mAssetAtlas);
52 }
53 
layerLostGlContext(Layer * layer)54 static void layerLostGlContext(Layer* layer) {
55     layer->onGlContextLost();
56 }
57 
onGLContextDestroyed()58 void RenderState::onGLContextDestroyed() {
59 /*
60     size_t size = mActiveLayers.size();
61     if (CC_UNLIKELY(size != 0)) {
62         ALOGE("Crashing, have %d contexts and %d layers at context destruction. isempty %d",
63                 mRegisteredContexts.size(), size, mActiveLayers.empty());
64         mCaches->dumpMemoryUsage();
65         for (std::set<renderthread::CanvasContext*>::iterator cit = mRegisteredContexts.begin();
66                 cit != mRegisteredContexts.end(); cit++) {
67             renderthread::CanvasContext* context = *cit;
68             ALOGE("Context: %p (root = %p)", context, context->mRootRenderNode.get());
69             ALOGE("  Prefeteched layers: %zu", context->mPrefetechedLayers.size());
70             for (std::set<RenderNode*>::iterator pit = context->mPrefetechedLayers.begin();
71                     pit != context->mPrefetechedLayers.end(); pit++) {
72                 (*pit)->debugDumpLayers("    ");
73             }
74             context->mRootRenderNode->debugDumpLayers("  ");
75         }
76 
77 
78         if (mActiveLayers.begin() == mActiveLayers.end()) {
79             ALOGE("set has become empty. wat.");
80         }
81         for (std::set<const Layer*>::iterator lit = mActiveLayers.begin();
82              lit != mActiveLayers.end(); lit++) {
83             const Layer* layer = *(lit);
84             ALOGE("Layer %p, state %d, texlayer %d, fbo %d, buildlayered %d",
85                     layer, layer->state, layer->isTextureLayer(), layer->getFbo(), layer->wasBuildLayered);
86         }
87         LOG_ALWAYS_FATAL("%d layers have survived gl context destruction", size);
88     }
89 */
90 
91     // TODO: reset all cached state in state objects
92     std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext);
93     mAssetAtlas.terminate();
94 
95     mCaches->terminate();
96 
97     delete mBlend;
98     mBlend = nullptr;
99     delete mMeshState;
100     mMeshState = nullptr;
101     delete mScissor;
102     mScissor = nullptr;
103     delete mStencil;
104     mStencil = nullptr;
105 }
106 
setViewport(GLsizei width,GLsizei height)107 void RenderState::setViewport(GLsizei width, GLsizei height) {
108     mViewportWidth = width;
109     mViewportHeight = height;
110     glViewport(0, 0, mViewportWidth, mViewportHeight);
111 }
112 
113 
getViewport(GLsizei * outWidth,GLsizei * outHeight)114 void RenderState::getViewport(GLsizei* outWidth, GLsizei* outHeight) {
115     *outWidth = mViewportWidth;
116     *outHeight = mViewportHeight;
117 }
118 
bindFramebuffer(GLuint fbo)119 void RenderState::bindFramebuffer(GLuint fbo) {
120     if (mFramebuffer != fbo) {
121         mFramebuffer = fbo;
122         glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
123     }
124 }
125 
invokeFunctor(Functor * functor,DrawGlInfo::Mode mode,DrawGlInfo * info)126 void RenderState::invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info) {
127     if (mode == DrawGlInfo::kModeProcessNoContext) {
128         // If there's no context we don't need to interrupt as there's
129         // no gl state to save/restore
130         (*functor)(mode, info);
131     } else {
132         interruptForFunctorInvoke();
133         (*functor)(mode, info);
134         resumeFromFunctorInvoke();
135     }
136 }
137 
interruptForFunctorInvoke()138 void RenderState::interruptForFunctorInvoke() {
139     mCaches->setProgram(nullptr);
140     mCaches->textureState().resetActiveTexture();
141     meshState().unbindMeshBuffer();
142     meshState().unbindIndicesBuffer();
143     meshState().resetVertexPointers();
144     meshState().disableTexCoordsVertexArray();
145     debugOverdraw(false, false);
146 }
147 
resumeFromFunctorInvoke()148 void RenderState::resumeFromFunctorInvoke() {
149     glViewport(0, 0, mViewportWidth, mViewportHeight);
150     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
151     debugOverdraw(false, false);
152 
153     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
154 
155     scissor().invalidate();
156     blend().invalidate();
157 
158     mCaches->textureState().activateTexture(0);
159     mCaches->textureState().resetBoundTextures();
160 }
161 
debugOverdraw(bool enable,bool clear)162 void RenderState::debugOverdraw(bool enable, bool clear) {
163     if (Properties::debugOverdraw && mFramebuffer == 0) {
164         if (clear) {
165             scissor().setEnabled(false);
166             stencil().clear();
167         }
168         if (enable) {
169             stencil().enableDebugWrite();
170         } else {
171             stencil().disable();
172         }
173     }
174 }
175 
requireGLContext()176 void RenderState::requireGLContext() {
177     assertOnGLThread();
178     LOG_ALWAYS_FATAL_IF(!mRenderThread.eglManager().hasEglContext(),
179             "No GL context!");
180 }
181 
assertOnGLThread()182 void RenderState::assertOnGLThread() {
183     pthread_t curr = pthread_self();
184     LOG_ALWAYS_FATAL_IF(!pthread_equal(mThreadId, curr), "Wrong thread!");
185 }
186 
187 class DecStrongTask : public renderthread::RenderTask {
188 public:
DecStrongTask(VirtualLightRefBase * object)189     DecStrongTask(VirtualLightRefBase* object) : mObject(object) {}
190 
run()191     virtual void run() override {
192         mObject->decStrong(nullptr);
193         mObject = nullptr;
194         delete this;
195     }
196 
197 private:
198     VirtualLightRefBase* mObject;
199 };
200 
postDecStrong(VirtualLightRefBase * object)201 void RenderState::postDecStrong(VirtualLightRefBase* object) {
202     mRenderThread.queue(new DecStrongTask(object));
203 }
204 
205 ///////////////////////////////////////////////////////////////////////////////
206 // Render
207 ///////////////////////////////////////////////////////////////////////////////
208 
render(const Glop & glop)209 void RenderState::render(const Glop& glop) {
210     const Glop::Mesh& mesh = glop.mesh;
211     const Glop::Mesh::Vertices& vertices = mesh.vertices;
212     const Glop::Mesh::Indices& indices = mesh.indices;
213     const Glop::Fill& fill = glop.fill;
214 
215     // ---------------------------------------------
216     // ---------- Program + uniform setup ----------
217     // ---------------------------------------------
218     mCaches->setProgram(fill.program);
219 
220     if (fill.colorEnabled) {
221         fill.program->setColor(fill.color);
222     }
223 
224     fill.program->set(glop.transform.ortho,
225             glop.transform.modelView,
226             glop.transform.meshTransform(),
227             glop.transform.transformFlags & TransformFlags::OffsetByFudgeFactor);
228 
229     // Color filter uniforms
230     if (fill.filterMode == ProgramDescription::kColorBlend) {
231         const FloatColor& color = fill.filter.color;
232         glUniform4f(mCaches->program().getUniform("colorBlend"),
233                 color.r, color.g, color.b, color.a);
234     } else if (fill.filterMode == ProgramDescription::kColorMatrix) {
235         glUniformMatrix4fv(mCaches->program().getUniform("colorMatrix"), 1, GL_FALSE,
236                 fill.filter.matrix.matrix);
237         glUniform4fv(mCaches->program().getUniform("colorMatrixVector"), 1,
238                 fill.filter.matrix.vector);
239     }
240 
241     // Round rect clipping uniforms
242     if (glop.roundRectClipState) {
243         // TODO: avoid query, and cache values (or RRCS ptr) in program
244         const RoundRectClipState* state = glop.roundRectClipState;
245         const Rect& innerRect = state->innerRect;
246         glUniform4f(fill.program->getUniform("roundRectInnerRectLTRB"),
247                 innerRect.left, innerRect.top,
248                 innerRect.right, innerRect.bottom);
249         glUniformMatrix4fv(fill.program->getUniform("roundRectInvTransform"),
250                 1, GL_FALSE, &state->matrix.data[0]);
251 
252         // add half pixel to round out integer rect space to cover pixel centers
253         float roundedOutRadius = state->radius + 0.5f;
254         glUniform1f(fill.program->getUniform("roundRectRadius"),
255                 roundedOutRadius);
256     }
257 
258     // --------------------------------
259     // ---------- Mesh setup ----------
260     // --------------------------------
261     // vertices
262     const bool force = meshState().bindMeshBufferInternal(vertices.bufferObject)
263             || (vertices.position != nullptr);
264     meshState().bindPositionVertexPointer(force, vertices.position, vertices.stride);
265 
266     // indices
267     meshState().bindIndicesBufferInternal(indices.bufferObject);
268 
269     if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
270         const Glop::Fill::TextureData& texture = fill.texture;
271         // texture always takes slot 0, shader samplers increment from there
272         mCaches->textureState().activateTexture(0);
273 
274         if (texture.clamp != GL_INVALID_ENUM) {
275             texture.texture->setWrap(texture.clamp, true, false, texture.target);
276         }
277         if (texture.filter != GL_INVALID_ENUM) {
278             texture.texture->setFilter(texture.filter, true, false, texture.target);
279         }
280 
281         mCaches->textureState().bindTexture(texture.target, texture.texture->id);
282         meshState().enableTexCoordsVertexArray();
283         meshState().bindTexCoordsVertexPointer(force, vertices.texCoord, vertices.stride);
284 
285         if (texture.textureTransform) {
286             glUniformMatrix4fv(fill.program->getUniform("mainTextureTransform"), 1,
287                     GL_FALSE, &texture.textureTransform->data[0]);
288         }
289     } else {
290         meshState().disableTexCoordsVertexArray();
291     }
292     int colorLocation = -1;
293     if (vertices.attribFlags & VertexAttribFlags::Color) {
294         colorLocation = fill.program->getAttrib("colors");
295         glEnableVertexAttribArray(colorLocation);
296         glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, vertices.stride, vertices.color);
297     }
298     int alphaLocation = -1;
299     if (vertices.attribFlags & VertexAttribFlags::Alpha) {
300         // NOTE: alpha vertex position is computed assuming no VBO
301         const void* alphaCoords = ((const GLbyte*) vertices.position) + kVertexAlphaOffset;
302         alphaLocation = fill.program->getAttrib("vtxAlpha");
303         glEnableVertexAttribArray(alphaLocation);
304         glVertexAttribPointer(alphaLocation, 1, GL_FLOAT, GL_FALSE, vertices.stride, alphaCoords);
305     }
306     // Shader uniforms
307     SkiaShader::apply(*mCaches, fill.skiaShaderData);
308 
309     // ------------------------------------
310     // ---------- GL state setup ----------
311     // ------------------------------------
312     blend().setFactors(glop.blend.src, glop.blend.dst);
313 
314     // ------------------------------------
315     // ---------- Actual drawing ----------
316     // ------------------------------------
317     if (indices.bufferObject == meshState().getQuadListIBO()) {
318         // Since the indexed quad list is of limited length, we loop over
319         // the glDrawXXX method while updating the vertex pointer
320         GLsizei elementsCount = mesh.elementCount;
321         const GLbyte* vertexData = static_cast<const GLbyte*>(vertices.position);
322         while (elementsCount > 0) {
323             GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
324 
325             // rebind pointers without forcing, since initial bind handled above
326             meshState().bindPositionVertexPointer(false, vertexData, vertices.stride);
327             if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
328                 meshState().bindTexCoordsVertexPointer(false,
329                         vertexData + kMeshTextureOffset, vertices.stride);
330             }
331 
332             glDrawElements(mesh.primitiveMode, drawCount, GL_UNSIGNED_SHORT, nullptr);
333             elementsCount -= drawCount;
334             vertexData += (drawCount / 6) * 4 * vertices.stride;
335         }
336     } else if (indices.bufferObject || indices.indices) {
337         glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT, indices.indices);
338     } else {
339         glDrawArrays(mesh.primitiveMode, 0, mesh.elementCount);
340     }
341 
342     // -----------------------------------
343     // ---------- Mesh teardown ----------
344     // -----------------------------------
345     if (vertices.attribFlags & VertexAttribFlags::Alpha) {
346         glDisableVertexAttribArray(alphaLocation);
347     }
348     if (vertices.attribFlags & VertexAttribFlags::Color) {
349         glDisableVertexAttribArray(colorLocation);
350     }
351 }
352 
dump()353 void RenderState::dump() {
354     blend().dump();
355     meshState().dump();
356     scissor().dump();
357     stencil().dump();
358 }
359 
360 } /* namespace uirenderer */
361 } /* namespace android */
362