Framebuffer11.cpp (18105B)
1 // 2 // Copyright 2014 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // Framebuffer11.cpp: Implements the Framebuffer11 class. 8 9 #include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h" 10 11 #include "common/bitset_utils.h" 12 #include "common/debug.h" 13 #include "libANGLE/Context.h" 14 #include "libANGLE/Framebuffer.h" 15 #include "libANGLE/FramebufferAttachment.h" 16 #include "libANGLE/Texture.h" 17 #include "libANGLE/renderer/d3d/TextureD3D.h" 18 #include "libANGLE/renderer/d3d/d3d11/Buffer11.h" 19 #include "libANGLE/renderer/d3d/d3d11/Clear11.h" 20 #include "libANGLE/renderer/d3d/d3d11/Context11.h" 21 #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" 22 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" 23 #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" 24 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" 25 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" 26 27 using namespace angle; 28 29 namespace rx 30 { 31 32 namespace 33 { 34 angle::Result MarkAttachmentsDirty(const gl::Context *context, 35 const gl::FramebufferAttachment *attachment) 36 { 37 if (attachment->type() == GL_TEXTURE) 38 { 39 gl::Texture *texture = attachment->getTexture(); 40 41 TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture); 42 43 TextureStorage *texStorage = nullptr; 44 ANGLE_TRY(textureD3D->getNativeTexture(context, &texStorage)); 45 46 if (texStorage) 47 { 48 TextureStorage11 *texStorage11 = GetAs<TextureStorage11>(texStorage); 49 ASSERT(texStorage11); 50 51 texStorage11->markLevelDirty(attachment->mipLevel()); 52 } 53 } 54 55 return angle::Result::Continue; 56 } 57 58 UINT GetAttachmentLayer(const gl::FramebufferAttachment *attachment) 59 { 60 if (attachment->type() == GL_TEXTURE && 61 attachment->getTexture()->getType() == gl::TextureType::_3D) 62 { 63 return attachment->layer(); 64 } 65 return 0; 66 } 67 68 } // anonymous namespace 69 70 Framebuffer11::Framebuffer11(const gl::FramebufferState &data, Renderer11 *renderer) 71 : FramebufferD3D(data, renderer), mRenderer(renderer) 72 { 73 ASSERT(mRenderer != nullptr); 74 } 75 76 Framebuffer11::~Framebuffer11() {} 77 78 angle::Result Framebuffer11::markAttachmentsDirty(const gl::Context *context) const 79 { 80 const auto &colorAttachments = mState.getColorAttachments(); 81 for (size_t drawBuffer : mState.getEnabledDrawBuffers()) 82 { 83 const gl::FramebufferAttachment &colorAttachment = colorAttachments[drawBuffer]; 84 ASSERT(colorAttachment.isAttached()); 85 ANGLE_TRY(MarkAttachmentsDirty(context, &colorAttachment)); 86 } 87 88 const gl::FramebufferAttachment *dsAttachment = mState.getDepthOrStencilAttachment(); 89 if (dsAttachment) 90 { 91 ANGLE_TRY(MarkAttachmentsDirty(context, dsAttachment)); 92 } 93 94 return angle::Result::Continue; 95 } 96 97 angle::Result Framebuffer11::clearImpl(const gl::Context *context, 98 const ClearParameters &clearParams) 99 { 100 Clear11 *clearer = mRenderer->getClearer(); 101 102 const gl::FramebufferAttachment *colorAttachment = mState.getFirstColorAttachment(); 103 if (clearParams.scissorEnabled == true && colorAttachment != nullptr && 104 UsePresentPathFast(mRenderer, colorAttachment)) 105 { 106 // If the current framebuffer is using the default colorbuffer, and present path fast is 107 // active, and the scissor rect is enabled, then we should invert the scissor rect 108 // vertically 109 ClearParameters presentPathFastClearParams = clearParams; 110 gl::Extents framebufferSize = colorAttachment->getSize(); 111 presentPathFastClearParams.scissor.y = framebufferSize.height - 112 presentPathFastClearParams.scissor.y - 113 presentPathFastClearParams.scissor.height; 114 ANGLE_TRY(clearer->clearFramebuffer(context, presentPathFastClearParams, mState)); 115 } 116 else 117 { 118 ANGLE_TRY(clearer->clearFramebuffer(context, clearParams, mState)); 119 } 120 121 ANGLE_TRY(markAttachmentsDirty(context)); 122 123 return angle::Result::Continue; 124 } 125 126 angle::Result Framebuffer11::invalidate(const gl::Context *context, 127 size_t count, 128 const GLenum *attachments) 129 { 130 return invalidateBase(context, count, attachments, false); 131 } 132 133 angle::Result Framebuffer11::discard(const gl::Context *context, 134 size_t count, 135 const GLenum *attachments) 136 { 137 return invalidateBase(context, count, attachments, true); 138 } 139 140 angle::Result Framebuffer11::invalidateBase(const gl::Context *context, 141 size_t count, 142 const GLenum *attachments, 143 bool useEXTBehavior) const 144 { 145 ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported(); 146 147 if (!deviceContext1) 148 { 149 // DiscardView() is only supported on ID3D11DeviceContext1 150 return angle::Result::Continue; 151 } 152 153 bool foundDepth = false; 154 bool foundStencil = false; 155 156 for (size_t i = 0; i < count; ++i) 157 { 158 switch (attachments[i]) 159 { 160 // Handle depth and stencil attachments. Defer discarding until later. 161 case GL_DEPTH_STENCIL_ATTACHMENT: 162 foundDepth = true; 163 foundStencil = true; 164 break; 165 case GL_DEPTH_EXT: 166 case GL_DEPTH_ATTACHMENT: 167 foundDepth = true; 168 break; 169 case GL_STENCIL_EXT: 170 case GL_STENCIL_ATTACHMENT: 171 foundStencil = true; 172 break; 173 default: 174 { 175 // Handle color attachments 176 ASSERT((attachments[i] >= GL_COLOR_ATTACHMENT0 && 177 attachments[i] <= GL_COLOR_ATTACHMENT15) || 178 (attachments[i] == GL_COLOR)); 179 180 size_t colorIndex = 181 (attachments[i] == GL_COLOR ? 0u : (attachments[i] - GL_COLOR_ATTACHMENT0)); 182 const gl::FramebufferAttachment *colorAttachment = 183 mState.getColorAttachment(colorIndex); 184 if (colorAttachment) 185 { 186 ANGLE_TRY(invalidateAttachment(context, colorAttachment)); 187 } 188 break; 189 } 190 } 191 } 192 193 bool discardDepth = false; 194 bool discardStencil = false; 195 196 // The D3D11 renderer uses the same view for depth and stencil buffers, so we must be careful. 197 if (useEXTBehavior) 198 { 199 // In the extension, if the app discards only one of the depth and stencil attachments, but 200 // those are backed by the same packed_depth_stencil buffer, then both images become 201 // undefined. 202 discardDepth = foundDepth; 203 204 // Don't bother discarding the stencil buffer if the depth buffer will already do it 205 discardStencil = foundStencil && (!discardDepth || mState.getDepthAttachment() == nullptr); 206 } 207 else 208 { 209 // In ES 3.0.4, if a specified attachment has base internal format DEPTH_STENCIL but the 210 // attachments list does not include DEPTH_STENCIL_ATTACHMENT or both DEPTH_ATTACHMENT and 211 // STENCIL_ATTACHMENT, then only the specified portion of every pixel in the subregion of 212 // pixels of the DEPTH_STENCIL buffer may be invalidated, and the other portion must be 213 // preserved. 214 discardDepth = (foundDepth && foundStencil) || 215 (foundDepth && (mState.getStencilAttachment() == nullptr)); 216 discardStencil = (foundStencil && (mState.getDepthAttachment() == nullptr)); 217 } 218 219 if (discardDepth && mState.getDepthAttachment()) 220 { 221 ANGLE_TRY(invalidateAttachment(context, mState.getDepthAttachment())); 222 } 223 224 if (discardStencil && mState.getStencilAttachment()) 225 { 226 ANGLE_TRY(invalidateAttachment(context, mState.getStencilAttachment())); 227 } 228 229 return angle::Result::Continue; 230 } 231 232 angle::Result Framebuffer11::invalidateSub(const gl::Context *context, 233 size_t count, 234 const GLenum *attachments, 235 const gl::Rectangle &area) 236 { 237 // A no-op implementation conforms to the spec, so don't call UNIMPLEMENTED() 238 return angle::Result::Continue; 239 } 240 241 angle::Result Framebuffer11::invalidateAttachment(const gl::Context *context, 242 const gl::FramebufferAttachment *attachment) const 243 { 244 ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported(); 245 ASSERT(deviceContext1); 246 ASSERT(attachment && attachment->isAttached()); 247 248 RenderTarget11 *renderTarget = nullptr; 249 ANGLE_TRY(attachment->getRenderTarget(context, 0, &renderTarget)); 250 const auto &rtv = renderTarget->getRenderTargetView(); 251 252 if (rtv.valid()) 253 { 254 deviceContext1->DiscardView(rtv.get()); 255 } 256 257 return angle::Result::Continue; 258 } 259 260 angle::Result Framebuffer11::readPixelsImpl(const gl::Context *context, 261 const gl::Rectangle &area, 262 GLenum format, 263 GLenum type, 264 size_t outputPitch, 265 const gl::PixelPackState &pack, 266 gl::Buffer *packBuffer, 267 uint8_t *pixels) 268 { 269 const gl::FramebufferAttachment *readAttachment = mState.getReadPixelsAttachment(format); 270 ASSERT(readAttachment); 271 272 if (packBuffer != nullptr) 273 { 274 Buffer11 *packBufferStorage = GetImplAs<Buffer11>(packBuffer); 275 const angle::Format &angleFormat = GetFormatFromFormatType(format, type); 276 PackPixelsParams packParams(area, angleFormat, static_cast<GLuint>(outputPitch), 277 pack.reverseRowOrder, packBuffer, 278 reinterpret_cast<ptrdiff_t>(pixels)); 279 280 return packBufferStorage->packPixels(context, *readAttachment, packParams); 281 } 282 283 return mRenderer->readFromAttachment(context, *readAttachment, area, format, type, 284 static_cast<GLuint>(outputPitch), pack, pixels); 285 } 286 287 angle::Result Framebuffer11::blitImpl(const gl::Context *context, 288 const gl::Rectangle &sourceArea, 289 const gl::Rectangle &destArea, 290 const gl::Rectangle *scissor, 291 bool blitRenderTarget, 292 bool blitDepth, 293 bool blitStencil, 294 GLenum filter, 295 const gl::Framebuffer *sourceFramebuffer) 296 { 297 if (blitRenderTarget) 298 { 299 const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getReadColorAttachment(); 300 ASSERT(readBuffer); 301 302 RenderTargetD3D *readRenderTarget = nullptr; 303 ANGLE_TRY(readBuffer->getRenderTarget(context, 0, &readRenderTarget)); 304 ASSERT(readRenderTarget); 305 306 const auto &colorAttachments = mState.getColorAttachments(); 307 const auto &drawBufferStates = mState.getDrawBufferStates(); 308 UINT readLayer = GetAttachmentLayer(readBuffer); 309 310 for (size_t colorAttachment = 0; colorAttachment < colorAttachments.size(); 311 colorAttachment++) 312 { 313 const gl::FramebufferAttachment &drawBuffer = colorAttachments[colorAttachment]; 314 315 if (drawBuffer.isAttached() && drawBufferStates[colorAttachment] != GL_NONE) 316 { 317 RenderTargetD3D *drawRenderTarget = nullptr; 318 ANGLE_TRY(drawBuffer.getRenderTarget( 319 context, drawBuffer.getRenderToTextureSamples(), &drawRenderTarget)); 320 ASSERT(drawRenderTarget); 321 322 const bool invertColorSource = UsePresentPathFast(mRenderer, readBuffer); 323 gl::Rectangle actualSourceArea = sourceArea; 324 if (invertColorSource) 325 { 326 RenderTarget11 *readRenderTarget11 = GetAs<RenderTarget11>(readRenderTarget); 327 actualSourceArea.y = readRenderTarget11->getHeight() - sourceArea.y; 328 actualSourceArea.height = -sourceArea.height; 329 } 330 331 const bool invertColorDest = UsePresentPathFast(mRenderer, &drawBuffer); 332 gl::Rectangle actualDestArea = destArea; 333 UINT drawLayer = GetAttachmentLayer(&drawBuffer); 334 335 const auto &surfaceTextureOffset = mState.getSurfaceTextureOffset(); 336 actualDestArea.x = actualDestArea.x + surfaceTextureOffset.x; 337 actualDestArea.y = actualDestArea.y + surfaceTextureOffset.y; 338 339 if (invertColorDest) 340 { 341 RenderTarget11 *drawRenderTarget11 = GetAs<RenderTarget11>(drawRenderTarget); 342 actualDestArea.y = drawRenderTarget11->getHeight() - destArea.y; 343 actualDestArea.height = -destArea.height; 344 } 345 346 ANGLE_TRY(mRenderer->blitRenderbufferRect(context, actualSourceArea, actualDestArea, 347 readLayer, drawLayer, readRenderTarget, 348 drawRenderTarget, filter, scissor, 349 blitRenderTarget, false, false)); 350 } 351 } 352 } 353 354 if (blitDepth || blitStencil) 355 { 356 const gl::FramebufferAttachment *readBuffer = 357 sourceFramebuffer->getDepthOrStencilAttachment(); 358 ASSERT(readBuffer); 359 RenderTargetD3D *readRenderTarget = nullptr; 360 ANGLE_TRY(readBuffer->getRenderTarget(context, 0, &readRenderTarget)); 361 ASSERT(readRenderTarget); 362 363 const bool invertSource = UsePresentPathFast(mRenderer, readBuffer); 364 gl::Rectangle actualSourceArea = sourceArea; 365 if (invertSource) 366 { 367 RenderTarget11 *readRenderTarget11 = GetAs<RenderTarget11>(readRenderTarget); 368 actualSourceArea.y = readRenderTarget11->getHeight() - sourceArea.y; 369 actualSourceArea.height = -sourceArea.height; 370 } 371 372 const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment(); 373 ASSERT(drawBuffer); 374 RenderTargetD3D *drawRenderTarget = nullptr; 375 ANGLE_TRY(drawBuffer->getRenderTarget(context, drawBuffer->getRenderToTextureSamples(), 376 &drawRenderTarget)); 377 ASSERT(drawRenderTarget); 378 379 bool invertDest = UsePresentPathFast(mRenderer, drawBuffer); 380 gl::Rectangle actualDestArea = destArea; 381 if (invertDest) 382 { 383 RenderTarget11 *drawRenderTarget11 = GetAs<RenderTarget11>(drawRenderTarget); 384 actualDestArea.y = drawRenderTarget11->getHeight() - destArea.y; 385 actualDestArea.height = -destArea.height; 386 } 387 388 ANGLE_TRY(mRenderer->blitRenderbufferRect(context, actualSourceArea, actualDestArea, 0, 0, 389 readRenderTarget, drawRenderTarget, filter, 390 scissor, false, blitDepth, blitStencil)); 391 } 392 393 ANGLE_TRY(markAttachmentsDirty(context)); 394 return angle::Result::Continue; 395 } 396 397 const gl::InternalFormat &Framebuffer11::getImplementationColorReadFormat( 398 const gl::Context *context) const 399 { 400 Context11 *context11 = GetImplAs<Context11>(context); 401 const Renderer11DeviceCaps &caps = context11->getRenderer()->getRenderer11DeviceCaps(); 402 GLenum sizedFormat = mState.getReadAttachment()->getFormat().info->sizedInternalFormat; 403 const angle::Format &angleFormat = d3d11::Format::Get(sizedFormat, caps).format(); 404 return gl::GetSizedInternalFormatInfo(angleFormat.fboImplementationInternalFormat); 405 } 406 407 angle::Result Framebuffer11::syncState(const gl::Context *context, 408 GLenum binding, 409 const gl::Framebuffer::DirtyBits &dirtyBits, 410 gl::Command command) 411 { 412 ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits)); 413 ANGLE_TRY(FramebufferD3D::syncState(context, binding, dirtyBits, command)); 414 415 // Call this last to allow the state manager to take advantage of the cached render targets. 416 mRenderer->getStateManager()->invalidateRenderTarget(); 417 418 // Call this to syncViewport for framebuffer default parameters. 419 if (mState.getDefaultWidth() != 0 || mState.getDefaultHeight() != 0) 420 { 421 mRenderer->getStateManager()->invalidateViewport(context); 422 } 423 424 return angle::Result::Continue; 425 } 426 427 angle::Result Framebuffer11::getSamplePosition(const gl::Context *context, 428 size_t index, 429 GLfloat *xy) const 430 { 431 const gl::FramebufferAttachment *attachment = mState.getFirstNonNullAttachment(); 432 ASSERT(attachment); 433 GLsizei sampleCount = attachment->getSamples(); 434 435 rx::GetSamplePosition(sampleCount, index, xy); 436 return angle::Result::Continue; 437 } 438 439 RenderTarget11 *Framebuffer11::getFirstRenderTarget() const 440 { 441 for (auto *renderTarget : mRenderTargetCache.getColors()) 442 { 443 if (renderTarget) 444 { 445 return renderTarget; 446 } 447 } 448 449 return mRenderTargetCache.getDepthStencil(); 450 } 451 452 } // namespace rx