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