• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // Framebuffer9.cpp: Implements the Framebuffer9 class.
8 
9 #include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h"
10 
11 #include "libANGLE/Context.h"
12 #include "libANGLE/Framebuffer.h"
13 #include "libANGLE/FramebufferAttachment.h"
14 #include "libANGLE/Texture.h"
15 #include "libANGLE/formatutils.h"
16 #include "libANGLE/renderer/ContextImpl.h"
17 #include "libANGLE/renderer/d3d/TextureD3D.h"
18 #include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
19 #include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
20 #include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h"
21 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
22 #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
23 #include "libANGLE/renderer/renderer_utils.h"
24 
25 namespace rx
26 {
Framebuffer9(const gl::FramebufferState & data,Renderer9 * renderer)27 Framebuffer9::Framebuffer9(const gl::FramebufferState &data, Renderer9 *renderer)
28     : FramebufferD3D(data, renderer), mRenderer(renderer)
29 {
30     ASSERT(mRenderer != nullptr);
31 }
32 
~Framebuffer9()33 Framebuffer9::~Framebuffer9() {}
34 
discard(const gl::Context * context,size_t count,const GLenum * attachments)35 angle::Result Framebuffer9::discard(const gl::Context *context,
36                                     size_t count,
37                                     const GLenum *attachments)
38 {
39     ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context));
40     return angle::Result::Stop;
41 }
42 
invalidate(const gl::Context * context,size_t count,const GLenum * attachments)43 angle::Result Framebuffer9::invalidate(const gl::Context *context,
44                                        size_t count,
45                                        const GLenum *attachments)
46 {
47     ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context));
48     return angle::Result::Stop;
49 }
50 
invalidateSub(const gl::Context * context,size_t count,const GLenum * attachments,const gl::Rectangle & area)51 angle::Result Framebuffer9::invalidateSub(const gl::Context *context,
52                                           size_t count,
53                                           const GLenum *attachments,
54                                           const gl::Rectangle &area)
55 {
56     ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context));
57     return angle::Result::Stop;
58 }
59 
clearImpl(const gl::Context * context,const ClearParameters & clearParams)60 angle::Result Framebuffer9::clearImpl(const gl::Context *context,
61                                       const ClearParameters &clearParams)
62 {
63     ANGLE_TRY(mRenderer->applyRenderTarget(context, mRenderTargetCache.getColors()[0],
64                                            mRenderTargetCache.getDepthStencil(true)));
65 
66     const gl::State &glState = context->getState();
67     float nearZ              = glState.getNearPlane();
68     float farZ               = glState.getFarPlane();
69     mRenderer->setViewport(glState.getViewport(), nearZ, farZ, gl::PrimitiveMode::Triangles,
70                            glState.getRasterizerState().frontFace, true);
71 
72     mRenderer->setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled());
73 
74     mRenderer->clear(clearParams, mRenderTargetCache.getColors()[0],
75                      mRenderTargetCache.getDepthStencil(true));
76     return angle::Result::Continue;
77 }
78 
readPixelsImpl(const gl::Context * context,const gl::Rectangle & area,GLenum format,GLenum type,size_t outputPitch,const gl::PixelPackState & pack,uint8_t * pixels)79 angle::Result Framebuffer9::readPixelsImpl(const gl::Context *context,
80                                            const gl::Rectangle &area,
81                                            GLenum format,
82                                            GLenum type,
83                                            size_t outputPitch,
84                                            const gl::PixelPackState &pack,
85                                            uint8_t *pixels)
86 {
87     const gl::FramebufferAttachment *colorbuffer = mState.getColorAttachment(0);
88     ASSERT(colorbuffer);
89 
90     RenderTarget9 *renderTarget = nullptr;
91     ANGLE_TRY(colorbuffer->getRenderTarget(context, 0, &renderTarget));
92     ASSERT(renderTarget);
93 
94     IDirect3DSurface9 *surface = renderTarget->getSurface();
95     ASSERT(surface);
96 
97     D3DSURFACE_DESC desc;
98     surface->GetDesc(&desc);
99 
100     Context9 *context9 = GetImplAs<Context9>(context);
101 
102     if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
103     {
104         UNIMPLEMENTED();  // FIXME: Requires resolve using StretchRect into non-multisampled render
105                           // target
106         SafeRelease(surface);
107         ANGLE_TRY_HR(context9, E_OUTOFMEMORY,
108                      "ReadPixels is unimplemented for multisampled framebuffer attachments.");
109     }
110 
111     IDirect3DDevice9 *device = mRenderer->getDevice();
112     ASSERT(device);
113 
114     HRESULT result;
115     IDirect3DSurface9 *systemSurface = nullptr;
116     bool directToPixels =
117         !pack.reverseRowOrder && pack.alignment <= 4 && mRenderer->getShareHandleSupport() &&
118         area.x == 0 && area.y == 0 && static_cast<UINT>(area.width) == desc.Width &&
119         static_cast<UINT>(area.height) == desc.Height && desc.Format == D3DFMT_A8R8G8B8 &&
120         format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE;
121     if (directToPixels)
122     {
123         // Use the pixels ptr as a shared handle to write directly into client's memory
124         result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
125                                                      D3DPOOL_SYSTEMMEM, &systemSurface,
126                                                      reinterpret_cast<void **>(&pixels));
127         if (FAILED(result))
128         {
129             // Try again without the shared handle
130             directToPixels = false;
131         }
132     }
133 
134     if (!directToPixels)
135     {
136         result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
137                                                      D3DPOOL_SYSTEMMEM, &systemSurface, nullptr);
138         if (FAILED(result))
139         {
140             ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
141             SafeRelease(surface);
142             ANGLE_TRY_HR(context9, E_OUTOFMEMORY,
143                          "Failed to allocate internal texture for ReadPixels.");
144         }
145     }
146 
147     result = device->GetRenderTargetData(surface, systemSurface);
148     SafeRelease(surface);
149 
150     if (FAILED(result))
151     {
152         SafeRelease(systemSurface);
153 
154         // It turns out that D3D will sometimes produce more error
155         // codes than those documented.
156         if (d3d9::isDeviceLostError(result))
157         {
158             mRenderer->notifyDeviceLost();
159         }
160         else
161         {
162             UNREACHABLE();
163         }
164 
165         ANGLE_TRY_HR(context9, E_OUTOFMEMORY, "Failed to read internal render target data.");
166     }
167 
168     if (directToPixels)
169     {
170         SafeRelease(systemSurface);
171         return angle::Result::Continue;
172     }
173 
174     RECT rect;
175     rect.left   = gl::clamp(area.x, 0L, static_cast<LONG>(desc.Width));
176     rect.top    = gl::clamp(area.y, 0L, static_cast<LONG>(desc.Height));
177     rect.right  = gl::clamp(area.x + area.width, 0L, static_cast<LONG>(desc.Width));
178     rect.bottom = gl::clamp(area.y + area.height, 0L, static_cast<LONG>(desc.Height));
179 
180     D3DLOCKED_RECT lock;
181     result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY);
182 
183     if (FAILED(result))
184     {
185         UNREACHABLE();
186         SafeRelease(systemSurface);
187 
188         ANGLE_TRY_HR(context9, E_OUTOFMEMORY, "Failed to lock internal render target.");
189     }
190 
191     uint8_t *source = static_cast<uint8_t *>(lock.pBits);
192     int inputPitch  = lock.Pitch;
193 
194     const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
195 
196     gl::FormatType formatType(format, type);
197 
198     PackPixelsParams packParams;
199     packParams.area.x          = rect.left;
200     packParams.area.y          = rect.top;
201     packParams.area.width      = rect.right - rect.left;
202     packParams.area.height     = rect.bottom - rect.top;
203     packParams.destFormat      = &GetFormatFromFormatType(format, type);
204     packParams.outputPitch     = static_cast<GLuint>(outputPitch);
205     packParams.reverseRowOrder = pack.reverseRowOrder;
206 
207     PackPixels(packParams, d3dFormatInfo.info(), inputPitch, source, pixels);
208 
209     systemSurface->UnlockRect();
210     SafeRelease(systemSurface);
211 
212     return angle::Result::Continue;
213 }
214 
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)215 angle::Result Framebuffer9::blitImpl(const gl::Context *context,
216                                      const gl::Rectangle &sourceArea,
217                                      const gl::Rectangle &destArea,
218                                      const gl::Rectangle *scissor,
219                                      bool blitRenderTarget,
220                                      bool blitDepth,
221                                      bool blitStencil,
222                                      GLenum filter,
223                                      const gl::Framebuffer *sourceFramebuffer)
224 {
225     ASSERT(filter == GL_NEAREST);
226 
227     IDirect3DDevice9 *device = mRenderer->getDevice();
228     ASSERT(device);
229 
230     mRenderer->endScene();
231 
232     Context9 *context9 = GetImplAs<Context9>(context);
233 
234     if (blitRenderTarget)
235     {
236         const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getColorAttachment(0);
237         ASSERT(readBuffer);
238 
239         RenderTarget9 *readRenderTarget = nullptr;
240         ANGLE_TRY(readBuffer->getRenderTarget(context, 0, &readRenderTarget));
241         ASSERT(readRenderTarget);
242 
243         const gl::FramebufferAttachment *drawBuffer = mState.getColorAttachment(0);
244         ASSERT(drawBuffer);
245 
246         RenderTarget9 *drawRenderTarget = nullptr;
247         ANGLE_TRY(
248             drawBuffer->getRenderTarget(context, drawBuffer->getSamples(), &drawRenderTarget));
249         ASSERT(drawRenderTarget);
250 
251         // The getSurface calls do an AddRef so save them until after no errors are possible
252         IDirect3DSurface9 *readSurface = readRenderTarget->getSurface();
253         ASSERT(readSurface);
254 
255         IDirect3DSurface9 *drawSurface = drawRenderTarget->getSurface();
256         ASSERT(drawSurface);
257 
258         gl::Extents srcSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1);
259         gl::Extents dstSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1);
260 
261         RECT srcRect;
262         srcRect.left   = sourceArea.x;
263         srcRect.right  = sourceArea.x + sourceArea.width;
264         srcRect.top    = sourceArea.y;
265         srcRect.bottom = sourceArea.y + sourceArea.height;
266 
267         RECT dstRect;
268         dstRect.left   = destArea.x;
269         dstRect.right  = destArea.x + destArea.width;
270         dstRect.top    = destArea.y;
271         dstRect.bottom = destArea.y + destArea.height;
272 
273         // Clip the rectangles to the scissor rectangle
274         if (scissor)
275         {
276             if (dstRect.left < scissor->x)
277             {
278                 srcRect.left += (scissor->x - dstRect.left);
279                 dstRect.left = scissor->x;
280             }
281             if (dstRect.top < scissor->y)
282             {
283                 srcRect.top += (scissor->y - dstRect.top);
284                 dstRect.top = scissor->y;
285             }
286             if (dstRect.right > scissor->x + scissor->width)
287             {
288                 srcRect.right -= (dstRect.right - (scissor->x + scissor->width));
289                 dstRect.right = scissor->x + scissor->width;
290             }
291             if (dstRect.bottom > scissor->y + scissor->height)
292             {
293                 srcRect.bottom -= (dstRect.bottom - (scissor->y + scissor->height));
294                 dstRect.bottom = scissor->y + scissor->height;
295             }
296         }
297 
298         // Clip the rectangles to the destination size
299         if (dstRect.left < 0)
300         {
301             srcRect.left += -dstRect.left;
302             dstRect.left = 0;
303         }
304         if (dstRect.right > dstSize.width)
305         {
306             srcRect.right -= (dstRect.right - dstSize.width);
307             dstRect.right = dstSize.width;
308         }
309         if (dstRect.top < 0)
310         {
311             srcRect.top += -dstRect.top;
312             dstRect.top = 0;
313         }
314         if (dstRect.bottom > dstSize.height)
315         {
316             srcRect.bottom -= (dstRect.bottom - dstSize.height);
317             dstRect.bottom = dstSize.height;
318         }
319 
320         // Clip the rectangles to the source size
321         if (srcRect.left < 0)
322         {
323             dstRect.left += -srcRect.left;
324             srcRect.left = 0;
325         }
326         if (srcRect.right > srcSize.width)
327         {
328             dstRect.right -= (srcRect.right - srcSize.width);
329             srcRect.right = srcSize.width;
330         }
331         if (srcRect.top < 0)
332         {
333             dstRect.top += -srcRect.top;
334             srcRect.top = 0;
335         }
336         if (srcRect.bottom > srcSize.height)
337         {
338             dstRect.bottom -= (srcRect.bottom - srcSize.height);
339             srcRect.bottom = srcSize.height;
340         }
341 
342         HRESULT result =
343             device->StretchRect(readSurface, &srcRect, drawSurface, &dstRect, D3DTEXF_NONE);
344 
345         SafeRelease(readSurface);
346         SafeRelease(drawSurface);
347 
348         ANGLE_TRY_HR(context9, result, "Internal blit failed.");
349     }
350 
351     if (blitDepth || blitStencil)
352     {
353         const gl::FramebufferAttachment *readBuffer =
354             sourceFramebuffer->getDepthOrStencilAttachment();
355         ASSERT(readBuffer);
356 
357         RenderTarget9 *readDepthStencil = nullptr;
358         ANGLE_TRY(readBuffer->getRenderTarget(context, 0, &readDepthStencil));
359         ASSERT(readDepthStencil);
360 
361         const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment();
362         ASSERT(drawBuffer);
363 
364         RenderTarget9 *drawDepthStencil = nullptr;
365         ANGLE_TRY(
366             drawBuffer->getRenderTarget(context, drawBuffer->getSamples(), &drawDepthStencil));
367         ASSERT(drawDepthStencil);
368 
369         // The getSurface calls do an AddRef so save them until after no errors are possible
370         IDirect3DSurface9 *readSurface = readDepthStencil->getSurface();
371         ASSERT(readDepthStencil);
372 
373         IDirect3DSurface9 *drawSurface = drawDepthStencil->getSurface();
374         ASSERT(drawDepthStencil);
375 
376         HRESULT result =
377             device->StretchRect(readSurface, nullptr, drawSurface, nullptr, D3DTEXF_NONE);
378 
379         SafeRelease(readSurface);
380         SafeRelease(drawSurface);
381 
382         ANGLE_TRY_HR(context9, result, "Internal blit failed.");
383     }
384 
385     return angle::Result::Continue;
386 }
387 
getImplementationColorReadFormat(const gl::Context * context) const388 const gl::InternalFormat &Framebuffer9::getImplementationColorReadFormat(
389     const gl::Context *context) const
390 {
391     GLenum sizedFormat = mState.getReadAttachment()->getFormat().info->sizedInternalFormat;
392     const d3d9::TextureFormat &textureFormat = d3d9::GetTextureFormatInfo(sizedFormat);
393     const d3d9::D3DFormat &d3dFormatInfo     = d3d9::GetD3DFormatInfo(textureFormat.renderFormat);
394     const angle::Format &angleFormat         = angle::Format::Get(d3dFormatInfo.formatID);
395     return gl::GetSizedInternalFormatInfo(angleFormat.fboImplementationInternalFormat);
396 }
397 
getSamplePosition(const gl::Context * context,size_t index,GLfloat * xy) const398 angle::Result Framebuffer9::getSamplePosition(const gl::Context *context,
399                                               size_t index,
400                                               GLfloat *xy) const
401 {
402     ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context));
403     return angle::Result::Stop;
404 }
405 
syncState(const gl::Context * context,GLenum binding,const gl::Framebuffer::DirtyBits & dirtyBits)406 angle::Result Framebuffer9::syncState(const gl::Context *context,
407                                       GLenum binding,
408                                       const gl::Framebuffer::DirtyBits &dirtyBits)
409 {
410     ANGLE_TRY(FramebufferD3D::syncState(context, binding, dirtyBits));
411     ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits));
412     return angle::Result::Continue;
413 }
414 }  // namespace rx
415