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 {
27
Framebuffer9(const gl::FramebufferState & data,Renderer9 * renderer)28 Framebuffer9::Framebuffer9(const gl::FramebufferState &data, Renderer9 *renderer)
29 : FramebufferD3D(data, renderer), mRenderer(renderer)
30 {
31 ASSERT(mRenderer != nullptr);
32 }
33
~Framebuffer9()34 Framebuffer9::~Framebuffer9()
35 {
36 }
37
discard(const gl::Context * context,size_t,const GLenum *)38 gl::Error Framebuffer9::discard(const gl::Context *context, size_t, const GLenum *)
39 {
40 // Extension not implemented in D3D9 renderer
41 UNREACHABLE();
42 return gl::NoError();
43 }
44
invalidate(const gl::Context * context,size_t,const GLenum *)45 gl::Error Framebuffer9::invalidate(const gl::Context *context, size_t, const GLenum *)
46 {
47 // Shouldn't ever reach here in D3D9
48 UNREACHABLE();
49 return gl::NoError();
50 }
51
invalidateSub(const gl::Context * context,size_t,const GLenum *,const gl::Rectangle &)52 gl::Error Framebuffer9::invalidateSub(const gl::Context *context,
53 size_t,
54 const GLenum *,
55 const gl::Rectangle &)
56 {
57 // Shouldn't ever reach here in D3D9
58 UNREACHABLE();
59 return gl::NoError();
60 }
61
clearImpl(const gl::Context * context,const ClearParameters & clearParams)62 gl::Error Framebuffer9::clearImpl(const gl::Context *context, const ClearParameters &clearParams)
63 {
64 const gl::FramebufferAttachment *colorAttachment = mState.getColorAttachment(0);
65 const gl::FramebufferAttachment *depthStencilAttachment = mState.getDepthOrStencilAttachment();
66
67 ANGLE_TRY(mRenderer->applyRenderTarget(context, colorAttachment, depthStencilAttachment));
68
69 const gl::State &glState = context->getGLState();
70 float nearZ = glState.getNearPlane();
71 float farZ = glState.getFarPlane();
72 mRenderer->setViewport(glState.getViewport(), nearZ, farZ, GL_TRIANGLES,
73 glState.getRasterizerState().frontFace, true);
74
75 mRenderer->setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled());
76
77 return mRenderer->clear(context, clearParams, colorAttachment, depthStencilAttachment);
78 }
79
readPixelsImpl(const gl::Context * context,const gl::Rectangle & area,GLenum format,GLenum type,size_t outputPitch,const gl::PixelPackState & pack,uint8_t * pixels)80 gl::Error Framebuffer9::readPixelsImpl(const gl::Context *context,
81 const gl::Rectangle &area,
82 GLenum format,
83 GLenum type,
84 size_t outputPitch,
85 const gl::PixelPackState &pack,
86 uint8_t *pixels)
87 {
88 const gl::FramebufferAttachment *colorbuffer = mState.getColorAttachment(0);
89 ASSERT(colorbuffer);
90
91 RenderTarget9 *renderTarget = nullptr;
92 ANGLE_TRY(colorbuffer->getRenderTarget(context, &renderTarget));
93 ASSERT(renderTarget);
94
95 IDirect3DSurface9 *surface = renderTarget->getSurface();
96 ASSERT(surface);
97
98 D3DSURFACE_DESC desc;
99 surface->GetDesc(&desc);
100
101 if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
102 {
103 UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target
104 SafeRelease(surface);
105 return gl::OutOfMemory()
106 << "ReadPixels is unimplemented for multisampled framebuffer attachments.";
107 }
108
109 IDirect3DDevice9 *device = mRenderer->getDevice();
110 ASSERT(device);
111
112 HRESULT result;
113 IDirect3DSurface9 *systemSurface = nullptr;
114 bool directToPixels = !pack.reverseRowOrder && pack.alignment <= 4 && mRenderer->getShareHandleSupport() &&
115 area.x == 0 && area.y == 0 &&
116 static_cast<UINT>(area.width) == desc.Width && static_cast<UINT>(area.height) == desc.Height &&
117 desc.Format == D3DFMT_A8R8G8B8 && format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE;
118 if (directToPixels)
119 {
120 // Use the pixels ptr as a shared handle to write directly into client's memory
121 result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
122 D3DPOOL_SYSTEMMEM, &systemSurface, reinterpret_cast<void**>(&pixels));
123 if (FAILED(result))
124 {
125 // Try again without the shared handle
126 directToPixels = false;
127 }
128 }
129
130 if (!directToPixels)
131 {
132 result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
133 D3DPOOL_SYSTEMMEM, &systemSurface, nullptr);
134 if (FAILED(result))
135 {
136 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
137 SafeRelease(surface);
138 return gl::OutOfMemory() << "Failed to allocate internal texture for ReadPixels.";
139 }
140 }
141
142 result = device->GetRenderTargetData(surface, systemSurface);
143 SafeRelease(surface);
144
145 if (FAILED(result))
146 {
147 SafeRelease(systemSurface);
148
149 // It turns out that D3D will sometimes produce more error
150 // codes than those documented.
151 if (d3d9::isDeviceLostError(result))
152 {
153 mRenderer->notifyDeviceLost();
154 }
155 else
156 {
157 UNREACHABLE();
158 }
159
160 return gl::OutOfMemory() << "Failed to read internal render target data.";
161 }
162
163 if (directToPixels)
164 {
165 SafeRelease(systemSurface);
166 return gl::NoError();
167 }
168
169 RECT rect;
170 rect.left = gl::clamp(area.x, 0L, static_cast<LONG>(desc.Width));
171 rect.top = gl::clamp(area.y, 0L, static_cast<LONG>(desc.Height));
172 rect.right = gl::clamp(area.x + area.width, 0L, static_cast<LONG>(desc.Width));
173 rect.bottom = gl::clamp(area.y + area.height, 0L, static_cast<LONG>(desc.Height));
174
175 D3DLOCKED_RECT lock;
176 result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY);
177
178 if (FAILED(result))
179 {
180 UNREACHABLE();
181 SafeRelease(systemSurface);
182
183 return gl::OutOfMemory() << "Failed to lock internal render target.";
184 }
185
186 uint8_t *source = reinterpret_cast<uint8_t *>(lock.pBits);
187 int inputPitch = lock.Pitch;
188
189 const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
190 gl::FormatType formatType(format, type);
191
192 PackPixelsParams packParams;
193 packParams.area.x = rect.left;
194 packParams.area.y = rect.top;
195 packParams.area.width = rect.right - rect.left;
196 packParams.area.height = rect.bottom - rect.top;
197 packParams.format = format;
198 packParams.type = type;
199 packParams.outputPitch = static_cast<GLuint>(outputPitch);
200 packParams.pack = pack;
201
202 PackPixels(packParams, d3dFormatInfo.info(), inputPitch, source, pixels);
203
204 systemSurface->UnlockRect();
205 SafeRelease(systemSurface);
206
207 return gl::NoError();
208 }
209
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)210 gl::Error Framebuffer9::blitImpl(const gl::Context *context,
211 const gl::Rectangle &sourceArea,
212 const gl::Rectangle &destArea,
213 const gl::Rectangle *scissor,
214 bool blitRenderTarget,
215 bool blitDepth,
216 bool blitStencil,
217 GLenum filter,
218 const gl::Framebuffer *sourceFramebuffer)
219 {
220 ASSERT(filter == GL_NEAREST);
221
222 IDirect3DDevice9 *device = mRenderer->getDevice();
223 ASSERT(device);
224
225 mRenderer->endScene();
226
227 if (blitRenderTarget)
228 {
229 const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getColorbuffer(0);
230 ASSERT(readBuffer);
231
232 RenderTarget9 *readRenderTarget = nullptr;
233 gl::Error error = readBuffer->getRenderTarget(context, &readRenderTarget);
234 if (error.isError())
235 {
236 return error;
237 }
238 ASSERT(readRenderTarget);
239
240 const gl::FramebufferAttachment *drawBuffer = mState.getColorAttachment(0);
241 ASSERT(drawBuffer);
242
243 RenderTarget9 *drawRenderTarget = nullptr;
244 error = drawBuffer->getRenderTarget(context, &drawRenderTarget);
245 if (error.isError())
246 {
247 return error;
248 }
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 = device->StretchRect(readSurface, &srcRect, drawSurface, &dstRect, D3DTEXF_NONE);
343
344 SafeRelease(readSurface);
345 SafeRelease(drawSurface);
346
347 if (FAILED(result))
348 {
349 return gl::OutOfMemory() << "Internal blit failed, StretchRect " << gl::FmtHR(result);
350 }
351 }
352
353 if (blitDepth || blitStencil)
354 {
355 const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getDepthOrStencilbuffer();
356 ASSERT(readBuffer);
357
358 RenderTarget9 *readDepthStencil = nullptr;
359 gl::Error error = readBuffer->getRenderTarget(context, &readDepthStencil);
360 if (error.isError())
361 {
362 return error;
363 }
364 ASSERT(readDepthStencil);
365
366 const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment();
367 ASSERT(drawBuffer);
368
369 RenderTarget9 *drawDepthStencil = nullptr;
370 error = drawBuffer->getRenderTarget(context, &drawDepthStencil);
371 if (error.isError())
372 {
373 return error;
374 }
375 ASSERT(drawDepthStencil);
376
377 // The getSurface calls do an AddRef so save them until after no errors are possible
378 IDirect3DSurface9* readSurface = readDepthStencil->getSurface();
379 ASSERT(readDepthStencil);
380
381 IDirect3DSurface9* drawSurface = drawDepthStencil->getSurface();
382 ASSERT(drawDepthStencil);
383
384 HRESULT result = device->StretchRect(readSurface, nullptr, drawSurface, nullptr, D3DTEXF_NONE);
385
386 SafeRelease(readSurface);
387 SafeRelease(drawSurface);
388
389 if (FAILED(result))
390 {
391 return gl::OutOfMemory() << "Internal blit failed, StretchRect " << gl::FmtHR(result);
392 }
393 }
394
395 return gl::NoError();
396 }
397
getRenderTargetImplementationFormat(RenderTargetD3D * renderTarget) const398 GLenum Framebuffer9::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const
399 {
400 RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTarget);
401 const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(renderTarget9->getD3DFormat());
402 return d3dFormatInfo.info().glInternalFormat;
403 }
404
getSamplePosition(size_t index,GLfloat * xy) const405 gl::Error Framebuffer9::getSamplePosition(size_t index, GLfloat *xy) const
406 {
407 UNREACHABLE();
408 return gl::InternalError() << "getSamplePosition is unsupported to d3d9.";
409 }
410
411 } // namespace rx
412