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 {
MarkAttachmentsDirty(const gl::Context * context,const gl::FramebufferAttachment * attachment)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
GetAttachmentLayer(const gl::FramebufferAttachment * attachment)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
Framebuffer11(const gl::FramebufferState & data,Renderer11 * renderer)70 Framebuffer11::Framebuffer11(const gl::FramebufferState &data, Renderer11 *renderer)
71 : FramebufferD3D(data, renderer), mRenderer(renderer)
72 {
73 ASSERT(mRenderer != nullptr);
74 }
75
~Framebuffer11()76 Framebuffer11::~Framebuffer11() {}
77
markAttachmentsDirty(const gl::Context * context) const78 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
clearImpl(const gl::Context * context,const ClearParameters & clearParams)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
invalidate(const gl::Context * context,size_t count,const GLenum * attachments)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
discard(const gl::Context * context,size_t count,const GLenum * attachments)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
invalidateBase(const gl::Context * context,size_t count,const GLenum * attachments,bool useEXTBehavior) const140 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
invalidateSub(const gl::Context * context,size_t count,const GLenum * attachments,const gl::Rectangle & area)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
invalidateAttachment(const gl::Context * context,const gl::FramebufferAttachment * attachment) const241 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 if (attachment->getDepthSize() > 0 || attachment->getStencilSize() > 0)
251 {
252 const auto &dsv = renderTarget->getDepthStencilView();
253 if (dsv.valid())
254 {
255 deviceContext1->DiscardView(dsv.get());
256 }
257 return angle::Result::Continue;
258 }
259 else
260 {
261 const auto &rtv = renderTarget->getRenderTargetView();
262
263 if (rtv.valid())
264 {
265 deviceContext1->DiscardView(rtv.get());
266 }
267
268 return angle::Result::Continue;
269 }
270 }
271
readPixelsImpl(const gl::Context * context,const gl::Rectangle & area,GLenum format,GLenum type,size_t outputPitch,const gl::PixelPackState & pack,gl::Buffer * packBuffer,uint8_t * pixels)272 angle::Result Framebuffer11::readPixelsImpl(const gl::Context *context,
273 const gl::Rectangle &area,
274 GLenum format,
275 GLenum type,
276 size_t outputPitch,
277 const gl::PixelPackState &pack,
278 gl::Buffer *packBuffer,
279 uint8_t *pixels)
280 {
281 const gl::FramebufferAttachment *readAttachment = mState.getReadPixelsAttachment(format);
282 ASSERT(readAttachment);
283
284 if (packBuffer != nullptr)
285 {
286 Buffer11 *packBufferStorage = GetImplAs<Buffer11>(packBuffer);
287 const angle::Format &angleFormat = GetFormatFromFormatType(format, type);
288 PackPixelsParams packParams(area, angleFormat, static_cast<GLuint>(outputPitch),
289 pack.reverseRowOrder, packBuffer,
290 reinterpret_cast<ptrdiff_t>(pixels));
291
292 return packBufferStorage->packPixels(context, *readAttachment, packParams);
293 }
294
295 return mRenderer->readFromAttachment(context, *readAttachment, area, format, type,
296 static_cast<GLuint>(outputPitch), pack, pixels);
297 }
298
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)299 angle::Result Framebuffer11::blitImpl(const gl::Context *context,
300 const gl::Rectangle &sourceArea,
301 const gl::Rectangle &destArea,
302 const gl::Rectangle *scissor,
303 bool blitRenderTarget,
304 bool blitDepth,
305 bool blitStencil,
306 GLenum filter,
307 const gl::Framebuffer *sourceFramebuffer)
308 {
309 if (blitRenderTarget)
310 {
311 const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getReadColorAttachment();
312 ASSERT(readBuffer);
313
314 RenderTargetD3D *readRenderTarget = nullptr;
315 ANGLE_TRY(readBuffer->getRenderTarget(context, 0, &readRenderTarget));
316 ASSERT(readRenderTarget);
317
318 const auto &colorAttachments = mState.getColorAttachments();
319 const auto &drawBufferStates = mState.getDrawBufferStates();
320 UINT readLayer = GetAttachmentLayer(readBuffer);
321
322 for (size_t colorAttachment = 0; colorAttachment < colorAttachments.size();
323 colorAttachment++)
324 {
325 const gl::FramebufferAttachment &drawBuffer = colorAttachments[colorAttachment];
326
327 if (drawBuffer.isAttached() && drawBufferStates[colorAttachment] != GL_NONE)
328 {
329 RenderTargetD3D *drawRenderTarget = nullptr;
330 ANGLE_TRY(drawBuffer.getRenderTarget(
331 context, drawBuffer.getRenderToTextureSamples(), &drawRenderTarget));
332 ASSERT(drawRenderTarget);
333
334 const bool invertColorSource = UsePresentPathFast(mRenderer, readBuffer);
335 gl::Rectangle actualSourceArea = sourceArea;
336 if (invertColorSource)
337 {
338 RenderTarget11 *readRenderTarget11 = GetAs<RenderTarget11>(readRenderTarget);
339 actualSourceArea.y = readRenderTarget11->getHeight() - sourceArea.y;
340 actualSourceArea.height = -sourceArea.height;
341 }
342
343 const bool invertColorDest = UsePresentPathFast(mRenderer, &drawBuffer);
344 gl::Rectangle actualDestArea = destArea;
345 UINT drawLayer = GetAttachmentLayer(&drawBuffer);
346
347 const auto &surfaceTextureOffset = mState.getSurfaceTextureOffset();
348 actualDestArea.x = actualDestArea.x + surfaceTextureOffset.x;
349 actualDestArea.y = actualDestArea.y + surfaceTextureOffset.y;
350
351 if (invertColorDest)
352 {
353 RenderTarget11 *drawRenderTarget11 = GetAs<RenderTarget11>(drawRenderTarget);
354 actualDestArea.y = drawRenderTarget11->getHeight() - destArea.y;
355 actualDestArea.height = -destArea.height;
356 }
357
358 ANGLE_TRY(mRenderer->blitRenderbufferRect(context, actualSourceArea, actualDestArea,
359 readLayer, drawLayer, readRenderTarget,
360 drawRenderTarget, filter, scissor,
361 blitRenderTarget, false, false));
362 }
363 }
364 }
365
366 if (blitDepth || blitStencil)
367 {
368 const gl::FramebufferAttachment *readBuffer =
369 sourceFramebuffer->getDepthOrStencilAttachment();
370 ASSERT(readBuffer);
371 RenderTargetD3D *readRenderTarget = nullptr;
372 ANGLE_TRY(readBuffer->getRenderTarget(context, 0, &readRenderTarget));
373 ASSERT(readRenderTarget);
374
375 const bool invertSource = UsePresentPathFast(mRenderer, readBuffer);
376 gl::Rectangle actualSourceArea = sourceArea;
377 if (invertSource)
378 {
379 RenderTarget11 *readRenderTarget11 = GetAs<RenderTarget11>(readRenderTarget);
380 actualSourceArea.y = readRenderTarget11->getHeight() - sourceArea.y;
381 actualSourceArea.height = -sourceArea.height;
382 }
383
384 const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment();
385 ASSERT(drawBuffer);
386 RenderTargetD3D *drawRenderTarget = nullptr;
387 ANGLE_TRY(drawBuffer->getRenderTarget(context, drawBuffer->getRenderToTextureSamples(),
388 &drawRenderTarget));
389 ASSERT(drawRenderTarget);
390
391 bool invertDest = UsePresentPathFast(mRenderer, drawBuffer);
392 gl::Rectangle actualDestArea = destArea;
393 if (invertDest)
394 {
395 RenderTarget11 *drawRenderTarget11 = GetAs<RenderTarget11>(drawRenderTarget);
396 actualDestArea.y = drawRenderTarget11->getHeight() - destArea.y;
397 actualDestArea.height = -destArea.height;
398 }
399
400 ANGLE_TRY(mRenderer->blitRenderbufferRect(context, actualSourceArea, actualDestArea, 0, 0,
401 readRenderTarget, drawRenderTarget, filter,
402 scissor, false, blitDepth, blitStencil));
403 }
404
405 ANGLE_TRY(markAttachmentsDirty(context));
406 return angle::Result::Continue;
407 }
408
getImplementationColorReadFormat(const gl::Context * context) const409 const gl::InternalFormat &Framebuffer11::getImplementationColorReadFormat(
410 const gl::Context *context) const
411 {
412 Context11 *context11 = GetImplAs<Context11>(context);
413 const Renderer11DeviceCaps &caps = context11->getRenderer()->getRenderer11DeviceCaps();
414 GLenum sizedFormat = mState.getReadAttachment()->getFormat().info->sizedInternalFormat;
415 const angle::Format &angleFormat = d3d11::Format::Get(sizedFormat, caps).format();
416 return gl::GetSizedInternalFormatInfo(angleFormat.fboImplementationInternalFormat);
417 }
418
syncState(const gl::Context * context,GLenum binding,const gl::Framebuffer::DirtyBits & dirtyBits,gl::Command command)419 angle::Result Framebuffer11::syncState(const gl::Context *context,
420 GLenum binding,
421 const gl::Framebuffer::DirtyBits &dirtyBits,
422 gl::Command command)
423 {
424 ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits));
425 ANGLE_TRY(FramebufferD3D::syncState(context, binding, dirtyBits, command));
426
427 // Call this last to allow the state manager to take advantage of the cached render targets.
428 mRenderer->getStateManager()->invalidateRenderTarget();
429
430 // Call this to syncViewport for framebuffer default parameters.
431 if (mState.getDefaultWidth() != 0 || mState.getDefaultHeight() != 0)
432 {
433 mRenderer->getStateManager()->invalidateViewport(context);
434 }
435
436 return angle::Result::Continue;
437 }
438
getSamplePosition(const gl::Context * context,size_t index,GLfloat * xy) const439 angle::Result Framebuffer11::getSamplePosition(const gl::Context *context,
440 size_t index,
441 GLfloat *xy) const
442 {
443 const gl::FramebufferAttachment *attachment = mState.getFirstNonNullAttachment();
444 ASSERT(attachment);
445 GLsizei sampleCount = attachment->getSamples();
446
447 rx::GetSamplePosition(sampleCount, index, xy);
448 return angle::Result::Continue;
449 }
450
getFirstRenderTarget() const451 RenderTarget11 *Framebuffer11::getFirstRenderTarget() const
452 {
453 for (auto *renderTarget : mRenderTargetCache.getColors())
454 {
455 if (renderTarget)
456 {
457 return renderTarget;
458 }
459 }
460
461 return mRenderTargetCache.getDepthStencil();
462 }
463
464 } // namespace rx
465