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