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