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