FramebufferD3D.cpp (15645B)
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 // FramebufferD3D.cpp: Implements the DefaultAttachmentD3D and FramebufferD3D classes. 8 9 #include "libANGLE/renderer/d3d/FramebufferD3D.h" 10 11 #include "common/bitset_utils.h" 12 #include "libANGLE/Context.h" 13 #include "libANGLE/ErrorStrings.h" 14 #include "libANGLE/Framebuffer.h" 15 #include "libANGLE/FramebufferAttachment.h" 16 #include "libANGLE/Surface.h" 17 #include "libANGLE/formatutils.h" 18 #include "libANGLE/renderer/ContextImpl.h" 19 #include "libANGLE/renderer/d3d/ContextD3D.h" 20 #include "libANGLE/renderer/d3d/RenderTargetD3D.h" 21 #include "libANGLE/renderer/d3d/RenderbufferD3D.h" 22 #include "libANGLE/renderer/d3d/RendererD3D.h" 23 #include "libANGLE/renderer/d3d/SurfaceD3D.h" 24 #include "libANGLE/renderer/d3d/SwapChainD3D.h" 25 #include "libANGLE/renderer/d3d/TextureD3D.h" 26 27 namespace rx 28 { 29 30 namespace 31 { 32 33 ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask) 34 { 35 ClearParameters clearParams; 36 memset(&clearParams, 0, sizeof(ClearParameters)); 37 38 clearParams.colorF = state.getColorClearValue(); 39 clearParams.colorType = GL_FLOAT; 40 clearParams.clearDepth = false; 41 clearParams.depthValue = state.getDepthClearValue(); 42 clearParams.clearStencil = false; 43 clearParams.stencilValue = state.getStencilClearValue(); 44 clearParams.stencilWriteMask = state.getDepthStencilState().stencilWritemask; 45 46 const auto *framebufferObject = state.getDrawFramebuffer(); 47 const gl::Extents &framebufferSize = framebufferObject->getFirstNonNullAttachment()->getSize(); 48 const gl::Offset &surfaceTextureOffset = framebufferObject->getSurfaceTextureOffset(); 49 if (state.isScissorTestEnabled()) 50 { 51 clearParams.scissorEnabled = true; 52 clearParams.scissor = state.getScissor(); 53 clearParams.scissor.x = clearParams.scissor.x + surfaceTextureOffset.x; 54 clearParams.scissor.y = clearParams.scissor.y + surfaceTextureOffset.y; 55 } 56 else if (surfaceTextureOffset != gl::kOffsetZero) 57 { 58 clearParams.scissorEnabled = true; 59 clearParams.scissor = gl::Rectangle(surfaceTextureOffset.x, surfaceTextureOffset.y, 60 framebufferSize.width, framebufferSize.height); 61 } 62 63 const bool clearColor = 64 (mask & GL_COLOR_BUFFER_BIT) && framebufferObject->hasEnabledDrawBuffer(); 65 if (clearColor) 66 { 67 clearParams.clearColor.set(); 68 } 69 else 70 { 71 clearParams.clearColor.reset(); 72 } 73 clearParams.colorMask = state.getBlendStateExt().getColorMaskBits(); 74 75 if (mask & GL_DEPTH_BUFFER_BIT) 76 { 77 if (state.getDepthStencilState().depthMask && 78 framebufferObject->getDepthAttachment() != nullptr) 79 { 80 clearParams.clearDepth = true; 81 } 82 } 83 84 if (mask & GL_STENCIL_BUFFER_BIT) 85 { 86 if (framebufferObject->getStencilAttachment() != nullptr && 87 framebufferObject->getStencilAttachment()->getStencilSize() > 0) 88 { 89 clearParams.clearStencil = true; 90 } 91 } 92 93 return clearParams; 94 } 95 } // namespace 96 97 ClearParameters::ClearParameters() = default; 98 99 ClearParameters::ClearParameters(const ClearParameters &other) = default; 100 101 FramebufferD3D::FramebufferD3D(const gl::FramebufferState &data, RendererD3D *renderer) 102 : FramebufferImpl(data), mRenderer(renderer), mMockAttachment() 103 {} 104 105 FramebufferD3D::~FramebufferD3D() {} 106 107 angle::Result FramebufferD3D::clear(const gl::Context *context, GLbitfield mask) 108 { 109 ClearParameters clearParams = GetClearParameters(context->getState(), mask); 110 return clearImpl(context, clearParams); 111 } 112 113 angle::Result FramebufferD3D::clearBufferfv(const gl::Context *context, 114 GLenum buffer, 115 GLint drawbuffer, 116 const GLfloat *values) 117 { 118 // glClearBufferfv can be called to clear the color buffer or depth buffer 119 ClearParameters clearParams = GetClearParameters(context->getState(), 0); 120 121 if (buffer == GL_COLOR) 122 { 123 for (unsigned int i = 0; i < clearParams.clearColor.size(); i++) 124 { 125 clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i)); 126 } 127 clearParams.colorF = gl::ColorF(values[0], values[1], values[2], values[3]); 128 clearParams.colorType = GL_FLOAT; 129 } 130 131 if (buffer == GL_DEPTH) 132 { 133 clearParams.clearDepth = true; 134 clearParams.depthValue = values[0]; 135 } 136 137 return clearImpl(context, clearParams); 138 } 139 140 angle::Result FramebufferD3D::clearBufferuiv(const gl::Context *context, 141 GLenum buffer, 142 GLint drawbuffer, 143 const GLuint *values) 144 { 145 // glClearBufferuiv can only be called to clear a color buffer 146 ClearParameters clearParams = GetClearParameters(context->getState(), 0); 147 for (unsigned int i = 0; i < clearParams.clearColor.size(); i++) 148 { 149 clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i)); 150 } 151 clearParams.colorUI = gl::ColorUI(values[0], values[1], values[2], values[3]); 152 clearParams.colorType = GL_UNSIGNED_INT; 153 154 return clearImpl(context, clearParams); 155 } 156 157 angle::Result FramebufferD3D::clearBufferiv(const gl::Context *context, 158 GLenum buffer, 159 GLint drawbuffer, 160 const GLint *values) 161 { 162 // glClearBufferiv can be called to clear the color buffer or stencil buffer 163 ClearParameters clearParams = GetClearParameters(context->getState(), 0); 164 165 if (buffer == GL_COLOR) 166 { 167 for (unsigned int i = 0; i < clearParams.clearColor.size(); i++) 168 { 169 clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i)); 170 } 171 clearParams.colorI = gl::ColorI(values[0], values[1], values[2], values[3]); 172 clearParams.colorType = GL_INT; 173 } 174 175 if (buffer == GL_STENCIL) 176 { 177 clearParams.clearStencil = true; 178 clearParams.stencilValue = values[0]; 179 } 180 181 return clearImpl(context, clearParams); 182 } 183 184 angle::Result FramebufferD3D::clearBufferfi(const gl::Context *context, 185 GLenum buffer, 186 GLint drawbuffer, 187 GLfloat depth, 188 GLint stencil) 189 { 190 // glClearBufferfi can only be called to clear a depth stencil buffer 191 ClearParameters clearParams = GetClearParameters(context->getState(), 0); 192 clearParams.clearDepth = true; 193 clearParams.depthValue = depth; 194 clearParams.clearStencil = true; 195 clearParams.stencilValue = stencil; 196 197 return clearImpl(context, clearParams); 198 } 199 200 angle::Result FramebufferD3D::readPixels(const gl::Context *context, 201 const gl::Rectangle &area, 202 GLenum format, 203 GLenum type, 204 const gl::PixelPackState &pack, 205 gl::Buffer *packBuffer, 206 void *pixels) 207 { 208 // Clip read area to framebuffer. 209 const gl::Extents fbSize = getState().getReadPixelsAttachment(format)->getSize(); 210 const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height); 211 gl::Rectangle clippedArea; 212 if (!ClipRectangle(area, fbRect, &clippedArea)) 213 { 214 // nothing to read 215 return angle::Result::Continue; 216 } 217 218 const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type); 219 220 ContextD3D *contextD3D = GetImplAs<ContextD3D>(context); 221 222 GLuint outputPitch = 0; 223 ANGLE_CHECK_GL_MATH(contextD3D, 224 sizedFormatInfo.computeRowPitch(type, area.width, pack.alignment, 225 pack.rowLength, &outputPitch)); 226 227 GLuint outputSkipBytes = 0; 228 ANGLE_CHECK_GL_MATH(contextD3D, sizedFormatInfo.computeSkipBytes(type, outputPitch, 0, pack, 229 false, &outputSkipBytes)); 230 outputSkipBytes += (clippedArea.x - area.x) * sizedFormatInfo.pixelBytes + 231 (clippedArea.y - area.y) * outputPitch; 232 233 return readPixelsImpl(context, clippedArea, format, type, outputPitch, pack, packBuffer, 234 static_cast<uint8_t *>(pixels) + outputSkipBytes); 235 } 236 237 angle::Result FramebufferD3D::blit(const gl::Context *context, 238 const gl::Rectangle &sourceArea, 239 const gl::Rectangle &destArea, 240 GLbitfield mask, 241 GLenum filter) 242 { 243 const auto &glState = context->getState(); 244 const gl::Framebuffer *sourceFramebuffer = glState.getReadFramebuffer(); 245 const gl::Rectangle *scissor = glState.isScissorTestEnabled() ? &glState.getScissor() : nullptr; 246 ANGLE_TRY(blitImpl(context, sourceArea, destArea, scissor, (mask & GL_COLOR_BUFFER_BIT) != 0, 247 (mask & GL_DEPTH_BUFFER_BIT) != 0, (mask & GL_STENCIL_BUFFER_BIT) != 0, 248 filter, sourceFramebuffer)); 249 250 return angle::Result::Continue; 251 } 252 253 gl::FramebufferStatus FramebufferD3D::checkStatus(const gl::Context *context) const 254 { 255 // if we have both a depth and stencil buffer, they must refer to the same object 256 // since we only support packed_depth_stencil and not separate depth and stencil 257 if (mState.hasSeparateDepthAndStencilAttachments()) 258 { 259 return gl::FramebufferStatus::Incomplete( 260 GL_FRAMEBUFFER_UNSUPPORTED, 261 gl::err::kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers); 262 } 263 264 // D3D11 does not allow for overlapping RenderTargetViews. 265 // If WebGL compatibility is enabled, this has already been checked at a higher level. 266 ASSERT(!context->isWebGL() || mState.colorAttachmentsAreUniqueImages()); 267 if (!context->isWebGL()) 268 { 269 if (!mState.colorAttachmentsAreUniqueImages()) 270 { 271 return gl::FramebufferStatus::Incomplete( 272 GL_FRAMEBUFFER_UNSUPPORTED, 273 gl::err::kFramebufferIncompleteUnsupportedNonUniqueAttachments); 274 } 275 } 276 277 // D3D requires all render targets to have the same dimensions. 278 if (!mState.attachmentsHaveSameDimensions()) 279 { 280 return gl::FramebufferStatus::Incomplete( 281 GL_FRAMEBUFFER_UNSUPPORTED, 282 gl::err::kFramebufferIncompleteUnsupportedMissmatchedDimensions); 283 } 284 285 return gl::FramebufferStatus::Complete(); 286 } 287 288 angle::Result FramebufferD3D::syncState(const gl::Context *context, 289 GLenum binding, 290 const gl::Framebuffer::DirtyBits &dirtyBits, 291 gl::Command command) 292 { 293 if (!mColorAttachmentsForRender.valid()) 294 { 295 return angle::Result::Continue; 296 } 297 298 for (auto dirtyBit : dirtyBits) 299 { 300 if ((dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 && 301 dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX) || 302 dirtyBit == gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS) 303 { 304 mColorAttachmentsForRender.reset(); 305 } 306 } 307 308 return angle::Result::Continue; 309 } 310 311 const gl::AttachmentList &FramebufferD3D::getColorAttachmentsForRender(const gl::Context *context) 312 { 313 gl::DrawBufferMask activeProgramOutputs = 314 context->getState().getProgram()->getExecutable().getActiveOutputVariablesMask(); 315 316 if (mColorAttachmentsForRender.valid() && mCurrentActiveProgramOutputs == activeProgramOutputs) 317 { 318 return mColorAttachmentsForRender.value(); 319 } 320 321 // Does not actually free memory 322 gl::AttachmentList colorAttachmentsForRender; 323 mColorAttachmentsForRenderMask.reset(); 324 325 const auto &colorAttachments = mState.getColorAttachments(); 326 const auto &drawBufferStates = mState.getDrawBufferStates(); 327 const auto &features = mRenderer->getFeatures(); 328 329 for (size_t attachmentIndex = 0; attachmentIndex < colorAttachments.size(); ++attachmentIndex) 330 { 331 GLenum drawBufferState = drawBufferStates[attachmentIndex]; 332 const gl::FramebufferAttachment &colorAttachment = colorAttachments[attachmentIndex]; 333 334 if (colorAttachment.isAttached() && drawBufferState != GL_NONE && 335 activeProgramOutputs[attachmentIndex]) 336 { 337 ASSERT(drawBufferState == GL_BACK || 338 drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + attachmentIndex)); 339 colorAttachmentsForRender.push_back(&colorAttachment); 340 mColorAttachmentsForRenderMask.set(attachmentIndex); 341 } 342 else if (!features.mrtPerfWorkaround.enabled) 343 { 344 colorAttachmentsForRender.push_back(nullptr); 345 mColorAttachmentsForRenderMask.set(attachmentIndex); 346 } 347 } 348 349 // When rendering with no render target on D3D, two bugs lead to incorrect behavior on Intel 350 // drivers < 4815. The rendering samples always pass neglecting discard statements in pixel 351 // shader. We add a mock texture as render target in such case. 352 if (mRenderer->getFeatures().addMockTextureNoRenderTarget.enabled && 353 colorAttachmentsForRender.empty() && activeProgramOutputs.any()) 354 { 355 static_assert(static_cast<size_t>(activeProgramOutputs.size()) <= 32, 356 "Size of active program outputs should less or equal than 32."); 357 const GLuint activeProgramLocation = static_cast<GLuint>( 358 gl::ScanForward(static_cast<uint32_t>(activeProgramOutputs.bits()))); 359 360 if (mMockAttachment.isAttached() && 361 (mMockAttachment.getBinding() - GL_COLOR_ATTACHMENT0) == activeProgramLocation) 362 { 363 colorAttachmentsForRender.push_back(&mMockAttachment); 364 } 365 else 366 { 367 // Remove mock attachment to prevents us from leaking it, and the program may require 368 // it to be attached to a new binding point. 369 if (mMockAttachment.isAttached()) 370 { 371 mMockAttachment.detach(context, Serial()); 372 } 373 374 gl::Texture *mockTex = nullptr; 375 // TODO(jmadill): Handle error if mock texture can't be created. 376 (void)mRenderer->getIncompleteTexture(context, gl::TextureType::_2D, &mockTex); 377 if (mockTex) 378 { 379 gl::ImageIndex index = gl::ImageIndex::Make2D(0); 380 mMockAttachment = gl::FramebufferAttachment( 381 context, GL_TEXTURE, GL_COLOR_ATTACHMENT0_EXT + activeProgramLocation, index, 382 mockTex, Serial()); 383 colorAttachmentsForRender.push_back(&mMockAttachment); 384 } 385 } 386 } 387 388 mColorAttachmentsForRender = std::move(colorAttachmentsForRender); 389 mCurrentActiveProgramOutputs = activeProgramOutputs; 390 391 return mColorAttachmentsForRender.value(); 392 } 393 394 void FramebufferD3D::destroy(const gl::Context *context) 395 { 396 if (mMockAttachment.isAttached()) 397 { 398 mMockAttachment.detach(context, Serial()); 399 } 400 } 401 402 } // namespace rx