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