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