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 #include <GpuMemoryTracker.h>
18 #include "DeferredLayerUpdater.h"
19 #include "GlLayer.h"
20 #include "VkLayer.h"
21 
22 #include "renderthread/CanvasContext.h"
23 #include "renderthread/EglManager.h"
24 #include "utils/GLUtils.h"
25 
26 #include <algorithm>
27 
28 #include <ui/ColorSpace.h>
29 
30 namespace android {
31 namespace uirenderer {
32 
RenderState(renderthread::RenderThread & thread)33 RenderState::RenderState(renderthread::RenderThread& thread)
34         : mRenderThread(thread), mViewportWidth(0), mViewportHeight(0), mFramebuffer(0) {
35     mThreadId = pthread_self();
36 }
37 
~RenderState()38 RenderState::~RenderState() {
39     LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
40                         "State object lifecycle not managed correctly");
41 }
42 
onGLContextCreated()43 void RenderState::onGLContextCreated() {
44     LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
45                         "State object lifecycle not managed correctly");
46     GpuMemoryTracker::onGpuContextCreated();
47 
48     mBlend = new Blend();
49     mMeshState = new MeshState();
50     mScissor = new Scissor();
51     mStencil = new Stencil();
52 
53     // Deferred because creation needs GL context for texture limits
54     if (!mLayerPool) {
55         mLayerPool = new OffscreenBufferPool();
56     }
57 
58     // This is delayed because the first access of Caches makes GL calls
59     if (!mCaches) {
60         mCaches = &Caches::createInstance(*this);
61     }
62     mCaches->init();
63 }
64 
layerLostGlContext(Layer * layer)65 static void layerLostGlContext(Layer* layer) {
66     LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::OpenGL,
67                         "layerLostGlContext on non GL layer");
68     static_cast<GlLayer*>(layer)->onGlContextLost();
69 }
70 
onGLContextDestroyed()71 void RenderState::onGLContextDestroyed() {
72     mLayerPool->clear();
73 
74     // TODO: reset all cached state in state objects
75     std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext);
76 
77     mCaches->terminate();
78 
79     delete mBlend;
80     mBlend = nullptr;
81     delete mMeshState;
82     mMeshState = nullptr;
83     delete mScissor;
84     mScissor = nullptr;
85     delete mStencil;
86     mStencil = nullptr;
87 
88     destroyLayersInUpdater();
89     GpuMemoryTracker::onGpuContextDestroyed();
90 }
91 
onVkContextCreated()92 void RenderState::onVkContextCreated() {
93     LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
94                         "State object lifecycle not managed correctly");
95     GpuMemoryTracker::onGpuContextCreated();
96 }
97 
layerDestroyedVkContext(Layer * layer)98 static void layerDestroyedVkContext(Layer* layer) {
99     LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::Vulkan,
100                         "layerLostVkContext on non Vulkan layer");
101     static_cast<VkLayer*>(layer)->onVkContextDestroyed();
102 }
103 
onVkContextDestroyed()104 void RenderState::onVkContextDestroyed() {
105     std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerDestroyedVkContext);
106     destroyLayersInUpdater();
107     GpuMemoryTracker::onGpuContextDestroyed();
108 }
109 
getGrContext() const110 GrContext* RenderState::getGrContext() const {
111     return mRenderThread.getGrContext();
112 }
113 
flush(Caches::FlushMode mode)114 void RenderState::flush(Caches::FlushMode mode) {
115     switch (mode) {
116         case Caches::FlushMode::Full:
117         // fall through
118         case Caches::FlushMode::Moderate:
119         // fall through
120         case Caches::FlushMode::Layers:
121             if (mLayerPool) mLayerPool->clear();
122             break;
123     }
124     if (mCaches) mCaches->flush(mode);
125 }
126 
onBitmapDestroyed(uint32_t pixelRefId)127 void RenderState::onBitmapDestroyed(uint32_t pixelRefId) {
128     if (mCaches && mCaches->textureCache.destroyTexture(pixelRefId)) {
129         glFlush();
130         GL_CHECKPOINT(MODERATE);
131     }
132 }
133 
setViewport(GLsizei width,GLsizei height)134 void RenderState::setViewport(GLsizei width, GLsizei height) {
135     mViewportWidth = width;
136     mViewportHeight = height;
137     glViewport(0, 0, mViewportWidth, mViewportHeight);
138 }
139 
getViewport(GLsizei * outWidth,GLsizei * outHeight)140 void RenderState::getViewport(GLsizei* outWidth, GLsizei* outHeight) {
141     *outWidth = mViewportWidth;
142     *outHeight = mViewportHeight;
143 }
144 
bindFramebuffer(GLuint fbo)145 void RenderState::bindFramebuffer(GLuint fbo) {
146     if (mFramebuffer != fbo) {
147         mFramebuffer = fbo;
148         glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
149     }
150 }
151 
createFramebuffer()152 GLuint RenderState::createFramebuffer() {
153     GLuint ret;
154     glGenFramebuffers(1, &ret);
155     return ret;
156 }
157 
deleteFramebuffer(GLuint fbo)158 void RenderState::deleteFramebuffer(GLuint fbo) {
159     if (mFramebuffer == fbo) {
160         // GL defines that deleting the currently bound FBO rebinds FBO 0.
161         // Reflect this in our cached value.
162         mFramebuffer = 0;
163     }
164     glDeleteFramebuffers(1, &fbo);
165 }
166 
invokeFunctor(Functor * functor,DrawGlInfo::Mode mode,DrawGlInfo * info)167 void RenderState::invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info) {
168     if (mode == DrawGlInfo::kModeProcessNoContext) {
169         // If there's no context we don't need to interrupt as there's
170         // no gl state to save/restore
171         (*functor)(mode, info);
172     } else {
173         interruptForFunctorInvoke();
174         (*functor)(mode, info);
175         resumeFromFunctorInvoke();
176     }
177 }
178 
interruptForFunctorInvoke()179 void RenderState::interruptForFunctorInvoke() {
180     mCaches->setProgram(nullptr);
181     mCaches->textureState().resetActiveTexture();
182     meshState().unbindMeshBuffer();
183     meshState().unbindIndicesBuffer();
184     meshState().resetVertexPointers();
185     meshState().disableTexCoordsVertexArray();
186     debugOverdraw(false, false);
187     // TODO: We need a way to know whether the functor is sRGB aware (b/32072673)
188     if (mCaches->extensions().hasLinearBlending() && mCaches->extensions().hasSRGBWriteControl()) {
189         glDisable(GL_FRAMEBUFFER_SRGB_EXT);
190     }
191 }
192 
resumeFromFunctorInvoke()193 void RenderState::resumeFromFunctorInvoke() {
194     if (mCaches->extensions().hasLinearBlending() && mCaches->extensions().hasSRGBWriteControl()) {
195         glEnable(GL_FRAMEBUFFER_SRGB_EXT);
196     }
197 
198     glViewport(0, 0, mViewportWidth, mViewportHeight);
199     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
200     debugOverdraw(false, false);
201 
202     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
203 
204     scissor().invalidate();
205     blend().invalidate();
206 
207     mCaches->textureState().activateTexture(0);
208     mCaches->textureState().resetBoundTextures();
209 }
210 
debugOverdraw(bool enable,bool clear)211 void RenderState::debugOverdraw(bool enable, bool clear) {
212     if (Properties::debugOverdraw && mFramebuffer == 0) {
213         if (clear) {
214             scissor().setEnabled(false);
215             stencil().clear();
216         }
217         if (enable) {
218             stencil().enableDebugWrite();
219         } else {
220             stencil().disable();
221         }
222     }
223 }
224 
destroyLayerInUpdater(DeferredLayerUpdater * layerUpdater)225 static void destroyLayerInUpdater(DeferredLayerUpdater* layerUpdater) {
226     layerUpdater->destroyLayer();
227 }
228 
destroyLayersInUpdater()229 void RenderState::destroyLayersInUpdater() {
230     std::for_each(mActiveLayerUpdaters.begin(), mActiveLayerUpdaters.end(), destroyLayerInUpdater);
231 }
232 
postDecStrong(VirtualLightRefBase * object)233 void RenderState::postDecStrong(VirtualLightRefBase* object) {
234     if (pthread_equal(mThreadId, pthread_self())) {
235         object->decStrong(nullptr);
236     } else {
237         mRenderThread.queue().post([object]() { object->decStrong(nullptr); });
238     }
239 }
240 
241 ///////////////////////////////////////////////////////////////////////////////
242 // Render
243 ///////////////////////////////////////////////////////////////////////////////
244 
render(const Glop & glop,const Matrix4 & orthoMatrix,bool overrideDisableBlending)245 void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix,
246                          bool overrideDisableBlending) {
247     const Glop::Mesh& mesh = glop.mesh;
248     const Glop::Mesh::Vertices& vertices = mesh.vertices;
249     const Glop::Mesh::Indices& indices = mesh.indices;
250     const Glop::Fill& fill = glop.fill;
251 
252     GL_CHECKPOINT(MODERATE);
253 
254     // ---------------------------------------------
255     // ---------- Program + uniform setup ----------
256     // ---------------------------------------------
257     mCaches->setProgram(fill.program);
258 
259     if (fill.colorEnabled) {
260         fill.program->setColor(fill.color);
261     }
262 
263     fill.program->set(orthoMatrix, glop.transform.modelView, glop.transform.meshTransform(),
264                       glop.transform.transformFlags & TransformFlags::OffsetByFudgeFactor);
265 
266     // Color filter uniforms
267     if (fill.filterMode == ProgramDescription::ColorFilterMode::Blend) {
268         const FloatColor& color = fill.filter.color;
269         glUniform4f(mCaches->program().getUniform("colorBlend"), color.r, color.g, color.b,
270                     color.a);
271     } else if (fill.filterMode == ProgramDescription::ColorFilterMode::Matrix) {
272         glUniformMatrix4fv(mCaches->program().getUniform("colorMatrix"), 1, GL_FALSE,
273                            fill.filter.matrix.matrix);
274         glUniform4fv(mCaches->program().getUniform("colorMatrixVector"), 1,
275                      fill.filter.matrix.vector);
276     }
277 
278     // Round rect clipping uniforms
279     if (glop.roundRectClipState) {
280         // TODO: avoid query, and cache values (or RRCS ptr) in program
281         const RoundRectClipState* state = glop.roundRectClipState;
282         const Rect& innerRect = state->innerRect;
283 
284         // add half pixel to round out integer rect space to cover pixel centers
285         float roundedOutRadius = state->radius + 0.5f;
286 
287         // Divide by the radius to simplify the calculations in the fragment shader
288         // roundRectPos is also passed from vertex shader relative to top/left & radius
289         glUniform4f(fill.program->getUniform("roundRectInnerRectLTWH"),
290                     innerRect.left / roundedOutRadius, innerRect.top / roundedOutRadius,
291                     (innerRect.right - innerRect.left) / roundedOutRadius,
292                     (innerRect.bottom - innerRect.top) / roundedOutRadius);
293 
294         glUniformMatrix4fv(fill.program->getUniform("roundRectInvTransform"), 1, GL_FALSE,
295                            &state->matrix.data[0]);
296 
297         glUniform1f(fill.program->getUniform("roundRectRadius"), roundedOutRadius);
298     }
299 
300     GL_CHECKPOINT(MODERATE);
301 
302     // --------------------------------
303     // ---------- Mesh setup ----------
304     // --------------------------------
305     // vertices
306     meshState().bindMeshBuffer(vertices.bufferObject);
307     meshState().bindPositionVertexPointer(vertices.position, vertices.stride);
308 
309     // indices
310     meshState().bindIndicesBuffer(indices.bufferObject);
311 
312     // texture
313     if (fill.texture.texture != nullptr) {
314         const Glop::Fill::TextureData& texture = fill.texture;
315         // texture always takes slot 0, shader samplers increment from there
316         mCaches->textureState().activateTexture(0);
317 
318         mCaches->textureState().bindTexture(texture.texture->target(), texture.texture->id());
319         if (texture.clamp != GL_INVALID_ENUM) {
320             texture.texture->setWrap(texture.clamp, false, false);
321         }
322         if (texture.filter != GL_INVALID_ENUM) {
323             texture.texture->setFilter(texture.filter, false, false);
324         }
325 
326         if (texture.textureTransform) {
327             glUniformMatrix4fv(fill.program->getUniform("mainTextureTransform"), 1, GL_FALSE,
328                                &texture.textureTransform->data[0]);
329         }
330     }
331 
332     // vertex attributes (tex coord, color, alpha)
333     if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
334         meshState().enableTexCoordsVertexArray();
335         meshState().bindTexCoordsVertexPointer(vertices.texCoord, vertices.stride);
336     } else {
337         meshState().disableTexCoordsVertexArray();
338     }
339     int colorLocation = -1;
340     if (vertices.attribFlags & VertexAttribFlags::Color) {
341         colorLocation = fill.program->getAttrib("colors");
342         glEnableVertexAttribArray(colorLocation);
343         glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, vertices.stride,
344                               vertices.color);
345     }
346     int alphaLocation = -1;
347     if (vertices.attribFlags & VertexAttribFlags::Alpha) {
348         // NOTE: alpha vertex position is computed assuming no VBO
349         const void* alphaCoords = ((const GLbyte*)vertices.position) + kVertexAlphaOffset;
350         alphaLocation = fill.program->getAttrib("vtxAlpha");
351         glEnableVertexAttribArray(alphaLocation);
352         glVertexAttribPointer(alphaLocation, 1, GL_FLOAT, GL_FALSE, vertices.stride, alphaCoords);
353     }
354     // Shader uniforms
355     SkiaShader::apply(*mCaches, fill.skiaShaderData, mViewportWidth, mViewportHeight);
356 
357     GL_CHECKPOINT(MODERATE);
358     Texture* texture = (fill.skiaShaderData.skiaShaderType & kBitmap_SkiaShaderType)
359                                ? fill.skiaShaderData.bitmapData.bitmapTexture
360                                : nullptr;
361     const AutoTexture autoCleanup(texture);
362 
363     // If we have a shader and a base texture, the base texture is assumed to be an alpha mask
364     // which means the color space conversion applies to the shader's bitmap
365     Texture* colorSpaceTexture = texture != nullptr ? texture : fill.texture.texture;
366     if (colorSpaceTexture != nullptr) {
367         if (colorSpaceTexture->hasColorSpaceConversion()) {
368             const ColorSpaceConnector* connector = colorSpaceTexture->getColorSpaceConnector();
369             glUniformMatrix3fv(fill.program->getUniform("colorSpaceMatrix"), 1, GL_FALSE,
370                                connector->getTransform().asArray());
371         }
372 
373         TransferFunctionType transferFunction = colorSpaceTexture->getTransferFunctionType();
374         if (transferFunction != TransferFunctionType::None) {
375             const ColorSpaceConnector* connector = colorSpaceTexture->getColorSpaceConnector();
376             const ColorSpace& source = connector->getSource();
377 
378             switch (transferFunction) {
379                 case TransferFunctionType::None:
380                     break;
381                 case TransferFunctionType::Full:
382                     glUniform1fv(fill.program->getUniform("transferFunction"), 7,
383                                  reinterpret_cast<const float*>(&source.getTransferParameters().g));
384                     break;
385                 case TransferFunctionType::Limited:
386                     glUniform1fv(fill.program->getUniform("transferFunction"), 5,
387                                  reinterpret_cast<const float*>(&source.getTransferParameters().g));
388                     break;
389                 case TransferFunctionType::Gamma:
390                     glUniform1f(fill.program->getUniform("transferFunctionGamma"),
391                                 source.getTransferParameters().g);
392                     break;
393             }
394         }
395     }
396 
397     // ------------------------------------
398     // ---------- GL state setup ----------
399     // ------------------------------------
400     if (CC_UNLIKELY(overrideDisableBlending)) {
401         blend().setFactors(GL_ZERO, GL_ZERO);
402     } else {
403         blend().setFactors(glop.blend.src, glop.blend.dst);
404     }
405 
406     GL_CHECKPOINT(MODERATE);
407 
408     // ------------------------------------
409     // ---------- Actual drawing ----------
410     // ------------------------------------
411     if (indices.bufferObject == meshState().getQuadListIBO()) {
412         // Since the indexed quad list is of limited length, we loop over
413         // the glDrawXXX method while updating the vertex pointer
414         GLsizei elementsCount = mesh.elementCount;
415         const GLbyte* vertexData = static_cast<const GLbyte*>(vertices.position);
416         while (elementsCount > 0) {
417             GLsizei drawCount = std::min(elementsCount, (GLsizei)kMaxNumberOfQuads * 6);
418             GLsizei vertexCount = (drawCount / 6) * 4;
419             meshState().bindPositionVertexPointer(vertexData, vertices.stride);
420             if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
421                 meshState().bindTexCoordsVertexPointer(vertexData + kMeshTextureOffset,
422                                                        vertices.stride);
423             }
424 
425             if (mCaches->extensions().getMajorGlVersion() >= 3) {
426                 glDrawRangeElements(mesh.primitiveMode, 0, vertexCount - 1, drawCount,
427                                     GL_UNSIGNED_SHORT, nullptr);
428             } else {
429                 glDrawElements(mesh.primitiveMode, drawCount, GL_UNSIGNED_SHORT, nullptr);
430             }
431             elementsCount -= drawCount;
432             vertexData += vertexCount * vertices.stride;
433         }
434     } else if (indices.bufferObject || indices.indices) {
435         if (mCaches->extensions().getMajorGlVersion() >= 3) {
436             // use glDrawRangeElements to reduce CPU overhead (otherwise the driver has to determine
437             // the min/max index values)
438             glDrawRangeElements(mesh.primitiveMode, 0, mesh.vertexCount - 1, mesh.elementCount,
439                                 GL_UNSIGNED_SHORT, indices.indices);
440         } else {
441             glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT,
442                            indices.indices);
443         }
444     } else {
445         glDrawArrays(mesh.primitiveMode, 0, mesh.elementCount);
446     }
447 
448     GL_CHECKPOINT(MODERATE);
449 
450     // -----------------------------------
451     // ---------- Mesh teardown ----------
452     // -----------------------------------
453     if (vertices.attribFlags & VertexAttribFlags::Alpha) {
454         glDisableVertexAttribArray(alphaLocation);
455     }
456     if (vertices.attribFlags & VertexAttribFlags::Color) {
457         glDisableVertexAttribArray(colorLocation);
458     }
459 
460     GL_CHECKPOINT(MODERATE);
461 }
462 
dump()463 void RenderState::dump() {
464     blend().dump();
465     meshState().dump();
466     scissor().dump();
467     stencil().dump();
468 }
469 
470 } /* namespace uirenderer */
471 } /* namespace android */
472