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