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