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