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/RenderTarget11.h"
21 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
22 #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
23 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
24 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
25
26 using namespace angle;
27
28 namespace rx
29 {
30
31 namespace
32 {
MarkAttachmentsDirty(const gl::Context * context,const gl::FramebufferAttachment * attachment)33 gl::Error MarkAttachmentsDirty(const gl::Context *context,
34 const gl::FramebufferAttachment *attachment)
35 {
36 if (attachment->type() == GL_TEXTURE)
37 {
38 gl::Texture *texture = attachment->getTexture();
39
40 TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture);
41
42 TextureStorage *texStorage = nullptr;
43 ANGLE_TRY(textureD3D->getNativeTexture(context, &texStorage));
44
45 if (texStorage)
46 {
47 TextureStorage11 *texStorage11 = GetAs<TextureStorage11>(texStorage);
48 ASSERT(texStorage11);
49
50 texStorage11->markLevelDirty(attachment->mipLevel());
51 }
52 }
53
54 return gl::NoError();
55 }
56
UpdateCachedRenderTarget(const gl::Context * context,const gl::FramebufferAttachment * attachment,RenderTarget11 * & cachedRenderTarget,OnRenderTargetDirtyBinding * channelBinding)57 void UpdateCachedRenderTarget(const gl::Context *context,
58 const gl::FramebufferAttachment *attachment,
59 RenderTarget11 *&cachedRenderTarget,
60 OnRenderTargetDirtyBinding *channelBinding)
61 {
62 RenderTarget11 *newRenderTarget = nullptr;
63 if (attachment)
64 {
65 // TODO(jmadill): Don't swallow this error.
66 gl::Error error = attachment->getRenderTarget(context, &newRenderTarget);
67 if (error.isError())
68 {
69 ERR() << "Internal rendertarget error: " << error;
70 }
71 }
72 if (newRenderTarget != cachedRenderTarget)
73 {
74 OnRenderTargetDirtyChannel *channel =
75 (newRenderTarget ? newRenderTarget->getBroadcastChannel() : nullptr);
76 channelBinding->bind(channel);
77 cachedRenderTarget = newRenderTarget;
78 }
79 }
80 } // anonymous namespace
81
Framebuffer11(const gl::FramebufferState & data,Renderer11 * renderer)82 Framebuffer11::Framebuffer11(const gl::FramebufferState &data, Renderer11 *renderer)
83 : FramebufferD3D(data, renderer),
84 mRenderer(renderer),
85 mCachedDepthStencilRenderTarget(nullptr),
86 mDepthStencilRenderTargetDirty(this, gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS)
87 {
88 ASSERT(mRenderer != nullptr);
89 mCachedColorRenderTargets.fill(nullptr);
90 for (size_t colorIndex = 0; colorIndex < data.getColorAttachments().size(); ++colorIndex)
91 {
92 mColorRenderTargetsDirty.emplace_back(this, colorIndex);
93 }
94 }
95
~Framebuffer11()96 Framebuffer11::~Framebuffer11()
97 {
98 }
99
markAttachmentsDirty(const gl::Context * context) const100 gl::Error Framebuffer11::markAttachmentsDirty(const gl::Context *context) const
101 {
102 const auto &colorAttachments = mState.getColorAttachments();
103 for (size_t drawBuffer : mState.getEnabledDrawBuffers())
104 {
105 const gl::FramebufferAttachment &colorAttachment = colorAttachments[drawBuffer];
106 ASSERT(colorAttachment.isAttached());
107 ANGLE_TRY(MarkAttachmentsDirty(context, &colorAttachment));
108 }
109
110 const gl::FramebufferAttachment *dsAttachment = mState.getDepthOrStencilAttachment();
111 if (dsAttachment)
112 {
113 ANGLE_TRY(MarkAttachmentsDirty(context, dsAttachment));
114 }
115
116 return gl::NoError();
117 }
118
clearImpl(const gl::Context * context,const ClearParameters & clearParams)119 gl::Error Framebuffer11::clearImpl(const gl::Context *context, const ClearParameters &clearParams)
120 {
121 Clear11 *clearer = mRenderer->getClearer();
122
123 const gl::FramebufferAttachment *colorAttachment = mState.getFirstColorAttachment();
124 if (clearParams.scissorEnabled == true && colorAttachment != nullptr &&
125 UsePresentPathFast(mRenderer, colorAttachment))
126 {
127 // If the current framebuffer is using the default colorbuffer, and present path fast is
128 // active, and the scissor rect is enabled, then we should invert the scissor rect
129 // vertically
130 ClearParameters presentPathFastClearParams = clearParams;
131 gl::Extents framebufferSize = colorAttachment->getSize();
132 presentPathFastClearParams.scissor.y = framebufferSize.height -
133 presentPathFastClearParams.scissor.y -
134 presentPathFastClearParams.scissor.height;
135 ANGLE_TRY(clearer->clearFramebuffer(context, presentPathFastClearParams, mState));
136 }
137 else
138 {
139 ANGLE_TRY(clearer->clearFramebuffer(context, clearParams, mState));
140 }
141
142 ANGLE_TRY(markAttachmentsDirty(context));
143
144 return gl::NoError();
145 }
146
invalidate(const gl::Context * context,size_t count,const GLenum * attachments)147 gl::Error Framebuffer11::invalidate(const gl::Context *context,
148 size_t count,
149 const GLenum *attachments)
150 {
151 return invalidateBase(context, count, attachments, false);
152 }
153
discard(const gl::Context * context,size_t count,const GLenum * attachments)154 gl::Error Framebuffer11::discard(const gl::Context *context,
155 size_t count,
156 const GLenum *attachments)
157 {
158 return invalidateBase(context, count, attachments, true);
159 }
160
invalidateBase(const gl::Context * context,size_t count,const GLenum * attachments,bool useEXTBehavior) const161 gl::Error Framebuffer11::invalidateBase(const gl::Context *context,
162 size_t count,
163 const GLenum *attachments,
164 bool useEXTBehavior) const
165 {
166 ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported();
167
168 if (!deviceContext1)
169 {
170 // DiscardView() is only supported on ID3D11DeviceContext1
171 return gl::NoError();
172 }
173
174 bool foundDepth = false;
175 bool foundStencil = false;
176
177 for (size_t i = 0; i < count; ++i)
178 {
179 switch (attachments[i])
180 {
181 // Handle depth and stencil attachments. Defer discarding until later.
182 case GL_DEPTH_STENCIL_ATTACHMENT:
183 foundDepth = true;
184 foundStencil = true;
185 break;
186 case GL_DEPTH_EXT:
187 case GL_DEPTH_ATTACHMENT:
188 foundDepth = true;
189 break;
190 case GL_STENCIL_EXT:
191 case GL_STENCIL_ATTACHMENT:
192 foundStencil = true;
193 break;
194 default:
195 {
196 // Handle color attachments
197 ASSERT((attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15) ||
198 (attachments[i] == GL_COLOR));
199
200 size_t colorIndex =
201 (attachments[i] == GL_COLOR ? 0u : (attachments[i] - GL_COLOR_ATTACHMENT0));
202 const gl::FramebufferAttachment *colorAttachment =
203 mState.getColorAttachment(colorIndex);
204 if (colorAttachment)
205 {
206 ANGLE_TRY(invalidateAttachment(context, colorAttachment));
207 }
208 break;
209 }
210 }
211 }
212
213 bool discardDepth = false;
214 bool discardStencil = false;
215
216 // The D3D11 renderer uses the same view for depth and stencil buffers, so we must be careful.
217 if (useEXTBehavior)
218 {
219 // In the extension, if the app discards only one of the depth and stencil attachments, but
220 // those are backed by the same packed_depth_stencil buffer, then both images become undefined.
221 discardDepth = foundDepth;
222
223 // Don't bother discarding the stencil buffer if the depth buffer will already do it
224 discardStencil = foundStencil && (!discardDepth || mState.getDepthAttachment() == nullptr);
225 }
226 else
227 {
228 // In ES 3.0.4, if a specified attachment has base internal format DEPTH_STENCIL but the
229 // attachments list does not include DEPTH_STENCIL_ATTACHMENT or both DEPTH_ATTACHMENT and
230 // STENCIL_ATTACHMENT, then only the specified portion of every pixel in the subregion of pixels
231 // of the DEPTH_STENCIL buffer may be invalidated, and the other portion must be preserved.
232 discardDepth = (foundDepth && foundStencil) ||
233 (foundDepth && (mState.getStencilAttachment() == nullptr));
234 discardStencil = (foundStencil && (mState.getDepthAttachment() == nullptr));
235 }
236
237 if (discardDepth && mState.getDepthAttachment())
238 {
239 ANGLE_TRY(invalidateAttachment(context, mState.getDepthAttachment()));
240 }
241
242 if (discardStencil && mState.getStencilAttachment())
243 {
244 ANGLE_TRY(invalidateAttachment(context, mState.getStencilAttachment()));
245 }
246
247 return gl::NoError();
248 }
249
invalidateSub(const gl::Context * context,size_t,const GLenum *,const gl::Rectangle &)250 gl::Error Framebuffer11::invalidateSub(const gl::Context *context,
251 size_t,
252 const GLenum *,
253 const gl::Rectangle &)
254 {
255 // A no-op implementation conforms to the spec, so don't call UNIMPLEMENTED()
256 return gl::NoError();
257 }
258
invalidateAttachment(const gl::Context * context,const gl::FramebufferAttachment * attachment) const259 gl::Error Framebuffer11::invalidateAttachment(const gl::Context *context,
260 const gl::FramebufferAttachment *attachment) const
261 {
262 ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported();
263 ASSERT(deviceContext1);
264 ASSERT(attachment && attachment->isAttached());
265
266 RenderTarget11 *renderTarget = nullptr;
267 ANGLE_TRY(attachment->getRenderTarget(context, &renderTarget));
268 const auto &rtv = renderTarget->getRenderTargetView();
269
270 if (rtv.valid())
271 {
272 deviceContext1->DiscardView(rtv.get());
273 }
274
275 return gl::NoError();
276 }
277
readPixelsImpl(const gl::Context * context,const gl::Rectangle & area,GLenum format,GLenum type,size_t outputPitch,const gl::PixelPackState & pack,uint8_t * pixels)278 gl::Error Framebuffer11::readPixelsImpl(const gl::Context *context,
279 const gl::Rectangle &area,
280 GLenum format,
281 GLenum type,
282 size_t outputPitch,
283 const gl::PixelPackState &pack,
284 uint8_t *pixels)
285 {
286 const gl::FramebufferAttachment *readAttachment = mState.getReadAttachment();
287 ASSERT(readAttachment);
288
289 gl::Buffer *packBuffer = context->getGLState().getTargetBuffer(gl::BufferBinding::PixelPack);
290 if (packBuffer != nullptr)
291 {
292 Buffer11 *packBufferStorage = GetImplAs<Buffer11>(packBuffer);
293 PackPixelsParams packParams(area, format, type, static_cast<GLuint>(outputPitch), pack,
294 packBuffer, reinterpret_cast<ptrdiff_t>(pixels));
295
296 return packBufferStorage->packPixels(context, *readAttachment, packParams);
297 }
298
299 return mRenderer->readFromAttachment(context, *readAttachment, area, format, type,
300 static_cast<GLuint>(outputPitch), pack, pixels);
301 }
302
blitImpl(const gl::Context * context,const gl::Rectangle & sourceArea,const gl::Rectangle & destArea,const gl::Rectangle * scissor,bool blitRenderTarget,bool blitDepth,bool blitStencil,GLenum filter,const gl::Framebuffer * sourceFramebuffer)303 gl::Error Framebuffer11::blitImpl(const gl::Context *context,
304 const gl::Rectangle &sourceArea,
305 const gl::Rectangle &destArea,
306 const gl::Rectangle *scissor,
307 bool blitRenderTarget,
308 bool blitDepth,
309 bool blitStencil,
310 GLenum filter,
311 const gl::Framebuffer *sourceFramebuffer)
312 {
313 if (blitRenderTarget)
314 {
315 const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getReadColorbuffer();
316 ASSERT(readBuffer);
317
318 RenderTargetD3D *readRenderTarget = nullptr;
319 ANGLE_TRY(readBuffer->getRenderTarget(context, &readRenderTarget));
320 ASSERT(readRenderTarget);
321
322 const auto &colorAttachments = mState.getColorAttachments();
323 const auto &drawBufferStates = mState.getDrawBufferStates();
324
325 for (size_t colorAttachment = 0; colorAttachment < colorAttachments.size(); colorAttachment++)
326 {
327 const gl::FramebufferAttachment &drawBuffer = colorAttachments[colorAttachment];
328
329 if (drawBuffer.isAttached() &&
330 drawBufferStates[colorAttachment] != GL_NONE)
331 {
332 RenderTargetD3D *drawRenderTarget = nullptr;
333 ANGLE_TRY(drawBuffer.getRenderTarget(context, &drawRenderTarget));
334 ASSERT(drawRenderTarget);
335
336 const bool invertColorSource = UsePresentPathFast(mRenderer, readBuffer);
337 gl::Rectangle actualSourceArea = sourceArea;
338 if (invertColorSource)
339 {
340 RenderTarget11 *readRenderTarget11 = GetAs<RenderTarget11>(readRenderTarget);
341 actualSourceArea.y = readRenderTarget11->getHeight() - sourceArea.y;
342 actualSourceArea.height = -sourceArea.height;
343 }
344
345 const bool invertColorDest = UsePresentPathFast(mRenderer, &drawBuffer);
346 gl::Rectangle actualDestArea = destArea;
347 if (invertColorDest)
348 {
349 RenderTarget11 *drawRenderTarget11 = GetAs<RenderTarget11>(drawRenderTarget);
350 actualDestArea.y = drawRenderTarget11->getHeight() - destArea.y;
351 actualDestArea.height = -destArea.height;
352 }
353
354 ANGLE_TRY(mRenderer->blitRenderbufferRect(
355 context, actualSourceArea, actualDestArea, readRenderTarget, drawRenderTarget,
356 filter, scissor, blitRenderTarget, false, false));
357 }
358 }
359 }
360
361 if (blitDepth || blitStencil)
362 {
363 const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getDepthOrStencilbuffer();
364 ASSERT(readBuffer);
365
366 RenderTargetD3D *readRenderTarget = nullptr;
367 ANGLE_TRY(readBuffer->getRenderTarget(context, &readRenderTarget));
368 ASSERT(readRenderTarget);
369
370 const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment();
371 ASSERT(drawBuffer);
372
373 RenderTargetD3D *drawRenderTarget = nullptr;
374 ANGLE_TRY(drawBuffer->getRenderTarget(context, &drawRenderTarget));
375 ASSERT(drawRenderTarget);
376
377 ANGLE_TRY(mRenderer->blitRenderbufferRect(context, sourceArea, destArea, readRenderTarget,
378 drawRenderTarget, filter, scissor, false,
379 blitDepth, blitStencil));
380 }
381
382 ANGLE_TRY(markAttachmentsDirty(context));
383 return gl::NoError();
384 }
385
getRenderTargetImplementationFormat(RenderTargetD3D * renderTarget) const386 GLenum Framebuffer11::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const
387 {
388 RenderTarget11 *renderTarget11 = GetAs<RenderTarget11>(renderTarget);
389 return renderTarget11->getFormatSet().format().fboImplementationInternalFormat;
390 }
391
updateColorRenderTarget(const gl::Context * context,size_t colorIndex)392 void Framebuffer11::updateColorRenderTarget(const gl::Context *context, size_t colorIndex)
393 {
394 UpdateCachedRenderTarget(context, mState.getColorAttachment(colorIndex),
395 mCachedColorRenderTargets[colorIndex],
396 &mColorRenderTargetsDirty[colorIndex]);
397 }
398
updateDepthStencilRenderTarget(const gl::Context * context)399 void Framebuffer11::updateDepthStencilRenderTarget(const gl::Context *context)
400 {
401 UpdateCachedRenderTarget(context, mState.getDepthOrStencilAttachment(),
402 mCachedDepthStencilRenderTarget, &mDepthStencilRenderTargetDirty);
403 }
404
syncState(const gl::Context * context,const gl::Framebuffer::DirtyBits & dirtyBits)405 void Framebuffer11::syncState(const gl::Context *context,
406 const gl::Framebuffer::DirtyBits &dirtyBits)
407 {
408 const auto &mergedDirtyBits = dirtyBits | mInternalDirtyBits;
409 mInternalDirtyBits.reset();
410
411 for (auto dirtyBit : mergedDirtyBits)
412 {
413 switch (dirtyBit)
414 {
415 case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
416 case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
417 updateDepthStencilRenderTarget(context);
418 break;
419 case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
420 case gl::Framebuffer::DIRTY_BIT_READ_BUFFER:
421 break;
422 case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
423 case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
424 case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES:
425 case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS:
426 break;
427 default:
428 {
429 ASSERT(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0 &&
430 dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX);
431 size_t colorIndex =
432 static_cast<size_t>(dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
433 updateColorRenderTarget(context, colorIndex);
434 break;
435 }
436 }
437 }
438
439 // We should not have dirtied any additional state during our sync.
440 ASSERT(!mInternalDirtyBits.any());
441
442 FramebufferD3D::syncState(context, dirtyBits);
443
444 // Call this last to allow the state manager to take advantage of the cached render targets.
445 mRenderer->getStateManager()->invalidateRenderTarget();
446
447 // Call this to syncViewport for framebuffer default parameters.
448 if (mState.getDefaultWidth() != 0 || mState.getDefaultHeight() != 0)
449 {
450 mRenderer->getStateManager()->invalidateViewport(context);
451 }
452 }
453
signal(size_t channelID,const gl::Context * context)454 void Framebuffer11::signal(size_t channelID, const gl::Context *context)
455 {
456 if (channelID == gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS)
457 {
458 // Stencil is redundant in this case.
459 mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT);
460 mCachedDepthStencilRenderTarget = nullptr;
461 }
462 else
463 {
464 mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 + channelID);
465 mCachedColorRenderTargets[channelID] = nullptr;
466 }
467
468 // Notify the context we need to re-validate the RenderTarget.
469 // TODO(jmadill): Check that we're the active draw framebuffer.
470 mRenderer->getStateManager()->invalidateRenderTarget();
471 }
472
getSamplePosition(size_t index,GLfloat * xy) const473 gl::Error Framebuffer11::getSamplePosition(size_t index, GLfloat *xy) const
474 {
475 const gl::FramebufferAttachment *attachment = mState.getFirstNonNullAttachment();
476 ASSERT(attachment);
477 GLsizei sampleCount = attachment->getSamples();
478
479 d3d11_gl::GetSamplePosition(sampleCount, index, xy);
480 return gl::NoError();
481 }
482
hasAnyInternalDirtyBit() const483 bool Framebuffer11::hasAnyInternalDirtyBit() const
484 {
485 return mInternalDirtyBits.any();
486 }
487
syncInternalState(const gl::Context * context)488 void Framebuffer11::syncInternalState(const gl::Context *context)
489 {
490 syncState(context, gl::Framebuffer::DirtyBits());
491 }
492
getFirstRenderTarget() const493 RenderTarget11 *Framebuffer11::getFirstRenderTarget() const
494 {
495 ASSERT(mInternalDirtyBits.none());
496 for (auto *renderTarget : mCachedColorRenderTargets)
497 {
498 if (renderTarget)
499 {
500 return renderTarget;
501 }
502 }
503
504 return mCachedDepthStencilRenderTarget;
505 }
506
507 } // namespace rx
508