1 //
2 // Copyright (c) 2002-2010 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 // Blit9.cpp: Surface copy utility class.
8
9 #include "libANGLE/renderer/d3d/d3d9/Blit9.h"
10
11 #include "libANGLE/renderer/d3d/TextureD3D.h"
12 #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
13 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
14 #include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h"
15 #include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
16 #include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
17 #include "libANGLE/angletypes.h"
18 #include "libANGLE/Framebuffer.h"
19 #include "libANGLE/FramebufferAttachment.h"
20
21 namespace
22 {
23 // Precompiled shaders
24 #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/standardvs.h"
25 #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/passthroughps.h"
26 #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceps.h"
27 #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminancepremultps.h"
28 #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceunmultps.h"
29 #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h"
30 #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskpremultps.h"
31 #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskunmultps.h"
32
33 const BYTE *const g_shaderCode[] = {
34 g_vs20_standardvs,
35 g_ps20_passthroughps,
36 g_ps20_luminanceps,
37 g_ps20_luminancepremultps,
38 g_ps20_luminanceunmultps,
39 g_ps20_componentmaskps,
40 g_ps20_componentmaskpremultps,
41 g_ps20_componentmaskunmultps,
42 };
43
44 const size_t g_shaderSize[] = {
45 sizeof(g_vs20_standardvs),
46 sizeof(g_ps20_passthroughps),
47 sizeof(g_ps20_luminanceps),
48 sizeof(g_ps20_luminancepremultps),
49 sizeof(g_ps20_luminanceunmultps),
50 sizeof(g_ps20_componentmaskps),
51 sizeof(g_ps20_componentmaskpremultps),
52 sizeof(g_ps20_componentmaskunmultps),
53 };
54 }
55
56 namespace rx
57 {
58
Blit9(Renderer9 * renderer)59 Blit9::Blit9(Renderer9 *renderer)
60 : mRenderer(renderer),
61 mGeometryLoaded(false),
62 mQuadVertexBuffer(nullptr),
63 mQuadVertexDeclaration(nullptr),
64 mSavedStateBlock(nullptr),
65 mSavedRenderTarget(nullptr),
66 mSavedDepthStencil(nullptr)
67 {
68 memset(mCompiledShaders, 0, sizeof(mCompiledShaders));
69 }
70
~Blit9()71 Blit9::~Blit9()
72 {
73 SafeRelease(mSavedStateBlock);
74 SafeRelease(mQuadVertexBuffer);
75 SafeRelease(mQuadVertexDeclaration);
76
77 for (int i = 0; i < SHADER_COUNT; i++)
78 {
79 SafeRelease(mCompiledShaders[i]);
80 }
81 }
82
initialize()83 gl::Error Blit9::initialize()
84 {
85 if (mGeometryLoaded)
86 {
87 return gl::NoError();
88 }
89
90 static const float quad[] =
91 {
92 -1, -1,
93 -1, 1,
94 1, -1,
95 1, 1
96 };
97
98 IDirect3DDevice9 *device = mRenderer->getDevice();
99
100 HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0,
101 D3DPOOL_DEFAULT, &mQuadVertexBuffer, nullptr);
102
103 if (FAILED(result))
104 {
105 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
106 return gl::OutOfMemory() << "Failed to create internal blit vertex shader, "
107 << gl::FmtHR(result);
108 }
109
110 void *lockPtr = nullptr;
111 result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0);
112
113 if (FAILED(result) || lockPtr == nullptr)
114 {
115 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
116 SafeRelease(mQuadVertexBuffer);
117 return gl::OutOfMemory() << "Failed to lock internal blit vertex shader, "
118 << gl::FmtHR(result);
119 }
120
121 memcpy(lockPtr, quad, sizeof(quad));
122 mQuadVertexBuffer->Unlock();
123
124 static const D3DVERTEXELEMENT9 elements[] =
125 {
126 { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
127 D3DDECL_END()
128 };
129
130 result = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration);
131
132 if (FAILED(result))
133 {
134 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
135 SafeRelease(mQuadVertexBuffer);
136 return gl::OutOfMemory() << "Failed to lock internal blit vertex declaration, "
137 << gl::FmtHR(result);
138 }
139
140 mGeometryLoaded = true;
141 return gl::NoError();
142 }
143
144 template <class D3DShaderType>
setShader(ShaderId source,const char * profile,gl::Error (Renderer9::* createShader)(const DWORD *,size_t length,D3DShaderType ** outShader),HRESULT (WINAPI IDirect3DDevice9::* setShader)(D3DShaderType *))145 gl::Error Blit9::setShader(ShaderId source, const char *profile,
146 gl::Error (Renderer9::*createShader)(const DWORD *, size_t length, D3DShaderType **outShader),
147 HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*))
148 {
149 IDirect3DDevice9 *device = mRenderer->getDevice();
150
151 D3DShaderType *shader = nullptr;
152
153 if (mCompiledShaders[source] != nullptr)
154 {
155 shader = static_cast<D3DShaderType*>(mCompiledShaders[source]);
156 }
157 else
158 {
159 const BYTE* shaderCode = g_shaderCode[source];
160 size_t shaderSize = g_shaderSize[source];
161 ANGLE_TRY((mRenderer->*createShader)(reinterpret_cast<const DWORD*>(shaderCode), shaderSize, &shader));
162 mCompiledShaders[source] = shader;
163 }
164
165 HRESULT hr = (device->*setShader)(shader);
166 if (FAILED(hr))
167 {
168 return gl::OutOfMemory() << "Failed to set shader for blit operation, " << gl::FmtHR(hr);
169 }
170
171 return gl::NoError();
172 }
173
setVertexShader(ShaderId shader)174 gl::Error Blit9::setVertexShader(ShaderId shader)
175 {
176 return setShader<IDirect3DVertexShader9>(shader, "vs_2_0", &Renderer9::createVertexShader, &IDirect3DDevice9::SetVertexShader);
177 }
178
setPixelShader(ShaderId shader)179 gl::Error Blit9::setPixelShader(ShaderId shader)
180 {
181 return setShader<IDirect3DPixelShader9>(shader, "ps_2_0", &Renderer9::createPixelShader, &IDirect3DDevice9::SetPixelShader);
182 }
183
getSurfaceRect(IDirect3DSurface9 * surface) const184 RECT Blit9::getSurfaceRect(IDirect3DSurface9 *surface) const
185 {
186 D3DSURFACE_DESC desc;
187 surface->GetDesc(&desc);
188
189 RECT rect;
190 rect.left = 0;
191 rect.top = 0;
192 rect.right = desc.Width;
193 rect.bottom = desc.Height;
194
195 return rect;
196 }
197
getSurfaceSize(IDirect3DSurface9 * surface) const198 gl::Extents Blit9::getSurfaceSize(IDirect3DSurface9 *surface) const
199 {
200 D3DSURFACE_DESC desc;
201 surface->GetDesc(&desc);
202
203 return gl::Extents(desc.Width, desc.Height, 1);
204 }
205
boxFilter(IDirect3DSurface9 * source,IDirect3DSurface9 * dest)206 gl::Error Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest)
207 {
208 ANGLE_TRY(initialize());
209
210 IDirect3DBaseTexture9 *texture = nullptr;
211 ANGLE_TRY(copySurfaceToTexture(source, getSurfaceRect(source), &texture));
212
213 IDirect3DDevice9 *device = mRenderer->getDevice();
214
215 saveState();
216
217 device->SetTexture(0, texture);
218 device->SetRenderTarget(0, dest);
219
220 ANGLE_TRY(setVertexShader(SHADER_VS_STANDARD));
221 ANGLE_TRY(setPixelShader(SHADER_PS_PASSTHROUGH));
222
223 setCommonBlitState();
224 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
225 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
226
227 setViewportAndShaderConstants(getSurfaceRect(source), getSurfaceSize(source),
228 getSurfaceRect(dest), false);
229
230 render();
231
232 SafeRelease(texture);
233
234 restoreState();
235
236 return gl::NoError();
237 }
238
copy2D(const gl::Context * context,const gl::Framebuffer * framebuffer,const RECT & sourceRect,GLenum destFormat,const gl::Offset & destOffset,TextureStorage * storage,GLint level)239 gl::Error Blit9::copy2D(const gl::Context *context,
240 const gl::Framebuffer *framebuffer,
241 const RECT &sourceRect,
242 GLenum destFormat,
243 const gl::Offset &destOffset,
244 TextureStorage *storage,
245 GLint level)
246 {
247 ANGLE_TRY(initialize());
248
249 const gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0);
250 ASSERT(colorbuffer);
251
252 RenderTarget9 *renderTarget9 = nullptr;
253 ANGLE_TRY(colorbuffer->getRenderTarget(context, &renderTarget9));
254 ASSERT(renderTarget9);
255
256 IDirect3DSurface9 *source = renderTarget9->getSurface();
257 ASSERT(source);
258
259 IDirect3DSurface9 *destSurface = nullptr;
260 TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
261 gl::Error error = storage9->getSurfaceLevel(context, GL_TEXTURE_2D, level, true, &destSurface);
262 if (error.isError())
263 {
264 SafeRelease(source);
265 return error;
266 }
267 ASSERT(destSurface);
268
269 gl::Error result =
270 copy(source, nullptr, sourceRect, destFormat, destOffset, destSurface, false, false, false);
271
272 SafeRelease(destSurface);
273 SafeRelease(source);
274
275 return result;
276 }
277
copyCube(const gl::Context * context,const gl::Framebuffer * framebuffer,const RECT & sourceRect,GLenum destFormat,const gl::Offset & destOffset,TextureStorage * storage,GLenum target,GLint level)278 gl::Error Blit9::copyCube(const gl::Context *context,
279 const gl::Framebuffer *framebuffer,
280 const RECT &sourceRect,
281 GLenum destFormat,
282 const gl::Offset &destOffset,
283 TextureStorage *storage,
284 GLenum target,
285 GLint level)
286 {
287 gl::Error error = initialize();
288 if (error.isError())
289 {
290 return error;
291 }
292
293 const gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0);
294 ASSERT(colorbuffer);
295
296 RenderTarget9 *renderTarget9 = nullptr;
297 error = colorbuffer->getRenderTarget(context, &renderTarget9);
298 if (error.isError())
299 {
300 return error;
301 }
302 ASSERT(renderTarget9);
303
304 IDirect3DSurface9 *source = renderTarget9->getSurface();
305 ASSERT(source);
306
307 IDirect3DSurface9 *destSurface = nullptr;
308 TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
309 error = storage9->getSurfaceLevel(context, target, level, true, &destSurface);
310 if (error.isError())
311 {
312 SafeRelease(source);
313 return error;
314 }
315 ASSERT(destSurface);
316
317 gl::Error result =
318 copy(source, nullptr, sourceRect, destFormat, destOffset, destSurface, false, false, false);
319
320 SafeRelease(destSurface);
321 SafeRelease(source);
322
323 return result;
324 }
325
copyTexture(const gl::Context * context,const gl::Texture * source,GLint sourceLevel,const RECT & sourceRect,GLenum destFormat,const gl::Offset & destOffset,TextureStorage * storage,GLenum destTarget,GLint destLevel,bool flipY,bool premultiplyAlpha,bool unmultiplyAlpha)326 gl::Error Blit9::copyTexture(const gl::Context *context,
327 const gl::Texture *source,
328 GLint sourceLevel,
329 const RECT &sourceRect,
330 GLenum destFormat,
331 const gl::Offset &destOffset,
332 TextureStorage *storage,
333 GLenum destTarget,
334 GLint destLevel,
335 bool flipY,
336 bool premultiplyAlpha,
337 bool unmultiplyAlpha)
338 {
339 ANGLE_TRY(initialize());
340
341 const TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
342
343 TextureStorage *sourceStorage = nullptr;
344 ANGLE_TRY(const_cast<TextureD3D *>(sourceD3D)->getNativeTexture(context, &sourceStorage));
345
346 TextureStorage9_2D *sourceStorage9 = GetAs<TextureStorage9_2D>(sourceStorage);
347 ASSERT(sourceStorage9);
348
349 TextureStorage9 *destStorage9 = GetAs<TextureStorage9>(storage);
350 ASSERT(destStorage9);
351
352 ASSERT(sourceLevel == 0);
353 IDirect3DBaseTexture9 *sourceTexture = nullptr;
354 ANGLE_TRY(sourceStorage9->getBaseTexture(context, &sourceTexture));
355
356 IDirect3DSurface9 *sourceSurface = nullptr;
357 ANGLE_TRY(
358 sourceStorage9->getSurfaceLevel(context, GL_TEXTURE_2D, sourceLevel, true, &sourceSurface));
359
360 IDirect3DSurface9 *destSurface = nullptr;
361 gl::Error error =
362 destStorage9->getSurfaceLevel(context, destTarget, destLevel, true, &destSurface);
363 if (error.isError())
364 {
365 SafeRelease(sourceSurface);
366 return error;
367 }
368
369 error = copy(sourceSurface, sourceTexture, sourceRect, destFormat, destOffset, destSurface,
370 flipY, premultiplyAlpha, unmultiplyAlpha);
371
372 SafeRelease(sourceSurface);
373 SafeRelease(destSurface);
374
375 return error;
376 }
377
copy(IDirect3DSurface9 * source,IDirect3DBaseTexture9 * sourceTexture,const RECT & sourceRect,GLenum destFormat,const gl::Offset & destOffset,IDirect3DSurface9 * dest,bool flipY,bool premultiplyAlpha,bool unmultiplyAlpha)378 gl::Error Blit9::copy(IDirect3DSurface9 *source,
379 IDirect3DBaseTexture9 *sourceTexture,
380 const RECT &sourceRect,
381 GLenum destFormat,
382 const gl::Offset &destOffset,
383 IDirect3DSurface9 *dest,
384 bool flipY,
385 bool premultiplyAlpha,
386 bool unmultiplyAlpha)
387 {
388 ASSERT(source != nullptr && dest != nullptr);
389
390 IDirect3DDevice9 *device = mRenderer->getDevice();
391
392 D3DSURFACE_DESC sourceDesc;
393 D3DSURFACE_DESC destDesc;
394 source->GetDesc(&sourceDesc);
395 dest->GetDesc(&destDesc);
396
397 // Check if it's possible to use StetchRect
398 if (sourceDesc.Format == destDesc.Format && (destDesc.Usage & D3DUSAGE_RENDERTARGET) &&
399 d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat) && !flipY &&
400 premultiplyAlpha == unmultiplyAlpha)
401 {
402 RECT destRect = { destOffset.x, destOffset.y, destOffset.x + (sourceRect.right - sourceRect.left), destOffset.y + (sourceRect.bottom - sourceRect.top)};
403 HRESULT result = device->StretchRect(source, &sourceRect, dest, &destRect, D3DTEXF_POINT);
404
405 if (FAILED(result))
406 {
407 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
408 return gl::OutOfMemory()
409 << "Failed to blit between textures, StretchRect " << gl::FmtHR(result);
410 }
411
412 return gl::NoError();
413 }
414 else
415 {
416 IDirect3DBaseTexture9 *texture = sourceTexture;
417 RECT adjustedSourceRect = sourceRect;
418 gl::Extents sourceSize(sourceDesc.Width, sourceDesc.Height, 1);
419
420 if (texture == nullptr)
421 {
422 ANGLE_TRY(copySurfaceToTexture(source, sourceRect, &texture));
423
424 // copySurfaceToTexture only copies in the sourceRect area of the source surface.
425 // Adjust sourceRect so that it is now covering the entire source texture
426 adjustedSourceRect.left = 0;
427 adjustedSourceRect.right = sourceRect.right - sourceRect.left;
428 adjustedSourceRect.top = 0;
429 adjustedSourceRect.bottom = sourceRect.bottom - sourceRect.top;
430
431 sourceSize.width = sourceRect.right - sourceRect.left;
432 sourceSize.height = sourceRect.bottom - sourceRect.top;
433 }
434 else
435 {
436 texture->AddRef();
437 }
438
439 gl::Error error = formatConvert(texture, adjustedSourceRect, sourceSize, destFormat,
440 destOffset, dest, flipY, premultiplyAlpha, unmultiplyAlpha);
441
442 SafeRelease(texture);
443
444 return error;
445 }
446 }
447
formatConvert(IDirect3DBaseTexture9 * source,const RECT & sourceRect,const gl::Extents & sourceSize,GLenum destFormat,const gl::Offset & destOffset,IDirect3DSurface9 * dest,bool flipY,bool premultiplyAlpha,bool unmultiplyAlpha)448 gl::Error Blit9::formatConvert(IDirect3DBaseTexture9 *source,
449 const RECT &sourceRect,
450 const gl::Extents &sourceSize,
451 GLenum destFormat,
452 const gl::Offset &destOffset,
453 IDirect3DSurface9 *dest,
454 bool flipY,
455 bool premultiplyAlpha,
456 bool unmultiplyAlpha)
457 {
458 ANGLE_TRY(initialize());
459
460 IDirect3DDevice9 *device = mRenderer->getDevice();
461
462 saveState();
463
464 device->SetTexture(0, source);
465 device->SetRenderTarget(0, dest);
466
467 RECT destRect;
468 destRect.left = destOffset.x;
469 destRect.right = destOffset.x + (sourceRect.right - sourceRect.left);
470 destRect.top = destOffset.y;
471 destRect.bottom = destOffset.y + (sourceRect.bottom - sourceRect.top);
472
473 setViewportAndShaderConstants(sourceRect, sourceSize, destRect, flipY);
474
475 setCommonBlitState();
476
477 gl::Error error = setFormatConvertShaders(destFormat, flipY, premultiplyAlpha, unmultiplyAlpha);
478 if (!error.isError())
479 {
480 render();
481 }
482
483 restoreState();
484
485 return error;
486 }
487
setFormatConvertShaders(GLenum destFormat,bool flipY,bool premultiplyAlpha,bool unmultiplyAlpha)488 gl::Error Blit9::setFormatConvertShaders(GLenum destFormat,
489 bool flipY,
490 bool premultiplyAlpha,
491 bool unmultiplyAlpha)
492 {
493 ANGLE_TRY(setVertexShader(SHADER_VS_STANDARD));
494
495 switch (destFormat)
496 {
497 case GL_RGBA:
498 case GL_BGRA_EXT:
499 case GL_RGB:
500 case GL_RG_EXT:
501 case GL_RED_EXT:
502 case GL_ALPHA:
503 if (premultiplyAlpha == unmultiplyAlpha)
504 {
505 ANGLE_TRY(setPixelShader(SHADER_PS_COMPONENTMASK));
506 }
507 else if (premultiplyAlpha)
508 {
509 ANGLE_TRY(setPixelShader(SHADER_PS_COMPONENTMASK_PREMULTIPLY_ALPHA));
510 }
511 else
512 {
513 ASSERT(unmultiplyAlpha);
514 ANGLE_TRY(setPixelShader(SHADER_PS_COMPONENTMASK_UNMULTIPLY_ALPHA));
515 }
516 break;
517
518 case GL_LUMINANCE:
519 case GL_LUMINANCE_ALPHA:
520 if (premultiplyAlpha == unmultiplyAlpha)
521 {
522 ANGLE_TRY(setPixelShader(SHADER_PS_LUMINANCE));
523 }
524 else if (premultiplyAlpha)
525 {
526 ANGLE_TRY(setPixelShader(SHADER_PS_LUMINANCE_PREMULTIPLY_ALPHA));
527 }
528 else
529 {
530 ASSERT(unmultiplyAlpha);
531 ANGLE_TRY(setPixelShader(SHADER_PS_LUMINANCE_UNMULTIPLY_ALPHA));
532 }
533 break;
534
535 default:
536 UNREACHABLE();
537 }
538
539 enum { X = 0, Y = 1, Z = 2, W = 3 };
540
541 // The meaning of this constant depends on the shader that was selected.
542 // See the shader assembly code above for details.
543 // Allocate one array for both registers and split it into two float4's.
544 float psConst[8] = { 0 };
545 float *multConst = &psConst[0];
546 float *addConst = &psConst[4];
547
548 switch (destFormat)
549 {
550 default: UNREACHABLE();
551 case GL_RGBA:
552 case GL_BGRA_EXT:
553 multConst[X] = 1;
554 multConst[Y] = 1;
555 multConst[Z] = 1;
556 multConst[W] = 1;
557 addConst[X] = 0;
558 addConst[Y] = 0;
559 addConst[Z] = 0;
560 addConst[W] = 0;
561 break;
562
563 case GL_RGB:
564 multConst[X] = 1;
565 multConst[Y] = 1;
566 multConst[Z] = 1;
567 multConst[W] = 0;
568 addConst[X] = 0;
569 addConst[Y] = 0;
570 addConst[Z] = 0;
571 addConst[W] = 1;
572 break;
573
574 case GL_RG_EXT:
575 multConst[X] = 1;
576 multConst[Y] = 1;
577 multConst[Z] = 0;
578 multConst[W] = 0;
579 addConst[X] = 0;
580 addConst[Y] = 0;
581 addConst[Z] = 0;
582 addConst[W] = 1;
583 break;
584
585 case GL_RED_EXT:
586 multConst[X] = 1;
587 multConst[Y] = 0;
588 multConst[Z] = 0;
589 multConst[W] = 0;
590 addConst[X] = 0;
591 addConst[Y] = 0;
592 addConst[Z] = 0;
593 addConst[W] = 1;
594 break;
595
596 case GL_ALPHA:
597 multConst[X] = 0;
598 multConst[Y] = 0;
599 multConst[Z] = 0;
600 multConst[W] = 1;
601 addConst[X] = 0;
602 addConst[Y] = 0;
603 addConst[Z] = 0;
604 addConst[W] = 0;
605 break;
606
607 case GL_LUMINANCE:
608 multConst[X] = 1;
609 multConst[Y] = 0;
610 multConst[Z] = 0;
611 multConst[W] = 0;
612 addConst[X] = 0;
613 addConst[Y] = 0;
614 addConst[Z] = 0;
615 addConst[W] = 1;
616 break;
617
618 case GL_LUMINANCE_ALPHA:
619 multConst[X] = 1;
620 multConst[Y] = 0;
621 multConst[Z] = 0;
622 multConst[W] = 1;
623 addConst[X] = 0;
624 addConst[Y] = 0;
625 addConst[Z] = 0;
626 addConst[W] = 0;
627 break;
628 }
629
630 mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst, 2);
631
632 return gl::NoError();
633 }
634
copySurfaceToTexture(IDirect3DSurface9 * surface,const RECT & sourceRect,IDirect3DBaseTexture9 ** outTexture)635 gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface,
636 const RECT &sourceRect,
637 IDirect3DBaseTexture9 **outTexture)
638 {
639 ASSERT(surface);
640
641 IDirect3DDevice9 *device = mRenderer->getDevice();
642
643 D3DSURFACE_DESC sourceDesc;
644 surface->GetDesc(&sourceDesc);
645
646 // Copy the render target into a texture
647 IDirect3DTexture9 *texture;
648 HRESULT result = device->CreateTexture(
649 sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1,
650 D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, nullptr);
651
652 if (FAILED(result))
653 {
654 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
655 return gl::OutOfMemory() << "Failed to allocate internal texture for blit, "
656 << gl::FmtHR(result);
657 }
658
659 IDirect3DSurface9 *textureSurface;
660 result = texture->GetSurfaceLevel(0, &textureSurface);
661
662 if (FAILED(result))
663 {
664 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
665 SafeRelease(texture);
666 return gl::OutOfMemory() << "Failed to query surface of internal blit texture, "
667 << gl::FmtHR(result);
668 }
669
670 mRenderer->endScene();
671 result = device->StretchRect(surface, &sourceRect, textureSurface, nullptr, D3DTEXF_NONE);
672
673 SafeRelease(textureSurface);
674
675 if (FAILED(result))
676 {
677 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
678 SafeRelease(texture);
679 return gl::OutOfMemory() << "Failed to copy between internal blit textures, "
680 << gl::FmtHR(result);
681 }
682
683 *outTexture = texture;
684 return gl::NoError();
685 }
686
setViewportAndShaderConstants(const RECT & sourceRect,const gl::Extents & sourceSize,const RECT & destRect,bool flipY)687 void Blit9::setViewportAndShaderConstants(const RECT &sourceRect,
688 const gl::Extents &sourceSize,
689 const RECT &destRect,
690 bool flipY)
691 {
692 IDirect3DDevice9 *device = mRenderer->getDevice();
693
694 D3DVIEWPORT9 vp;
695 vp.X = destRect.left;
696 vp.Y = destRect.top;
697 vp.Width = destRect.right - destRect.left;
698 vp.Height = destRect.bottom - destRect.top;
699 vp.MinZ = 0.0f;
700 vp.MaxZ = 1.0f;
701 device->SetViewport(&vp);
702
703 float vertexConstants[8] = {
704 // halfPixelAdjust
705 -1.0f / vp.Width, 1.0f / vp.Height, 0, 0,
706 // texcoordOffset
707 static_cast<float>(sourceRect.left) / sourceSize.width,
708 static_cast<float>(flipY ? sourceRect.bottom : sourceRect.top) / sourceSize.height,
709 static_cast<float>(sourceRect.right - sourceRect.left) / sourceSize.width,
710 static_cast<float>(flipY ? sourceRect.top - sourceRect.bottom
711 : sourceRect.bottom - sourceRect.top) /
712 sourceSize.height,
713 };
714
715 device->SetVertexShaderConstantF(0, vertexConstants, 2);
716 }
717
setCommonBlitState()718 void Blit9::setCommonBlitState()
719 {
720 IDirect3DDevice9 *device = mRenderer->getDevice();
721
722 device->SetDepthStencilSurface(nullptr);
723
724 device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
725 device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
726 device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
727 device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
728 device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
729 device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
730 device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
731 device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
732
733 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
734 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
735 device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE);
736 device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
737 device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
738
739 RECT scissorRect = {0}; // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle
740 device->SetScissorRect(&scissorRect);
741
742 for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
743 {
744 device->SetStreamSourceFreq(i, 1);
745 }
746 }
747
render()748 void Blit9::render()
749 {
750 IDirect3DDevice9 *device = mRenderer->getDevice();
751
752 HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float));
753 hr = device->SetVertexDeclaration(mQuadVertexDeclaration);
754
755 mRenderer->startScene();
756 hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
757 }
758
saveState()759 void Blit9::saveState()
760 {
761 IDirect3DDevice9 *device = mRenderer->getDevice();
762
763 HRESULT hr;
764
765 device->GetDepthStencilSurface(&mSavedDepthStencil);
766 device->GetRenderTarget(0, &mSavedRenderTarget);
767
768 if (mSavedStateBlock == nullptr)
769 {
770 hr = device->BeginStateBlock();
771 ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
772
773 setCommonBlitState();
774
775 static const float dummyConst[8] = { 0 };
776
777 device->SetVertexShader(nullptr);
778 device->SetVertexShaderConstantF(0, dummyConst, 2);
779 device->SetPixelShader(nullptr);
780 device->SetPixelShaderConstantF(0, dummyConst, 2);
781
782 D3DVIEWPORT9 dummyVp;
783 dummyVp.X = 0;
784 dummyVp.Y = 0;
785 dummyVp.Width = 1;
786 dummyVp.Height = 1;
787 dummyVp.MinZ = 0;
788 dummyVp.MaxZ = 1;
789
790 device->SetViewport(&dummyVp);
791
792 device->SetTexture(0, nullptr);
793
794 device->SetStreamSource(0, mQuadVertexBuffer, 0, 0);
795
796 device->SetVertexDeclaration(mQuadVertexDeclaration);
797
798 hr = device->EndStateBlock(&mSavedStateBlock);
799 ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
800 }
801
802 ASSERT(mSavedStateBlock != nullptr);
803
804 if (mSavedStateBlock != nullptr)
805 {
806 hr = mSavedStateBlock->Capture();
807 ASSERT(SUCCEEDED(hr));
808 }
809 }
810
restoreState()811 void Blit9::restoreState()
812 {
813 IDirect3DDevice9 *device = mRenderer->getDevice();
814
815 device->SetDepthStencilSurface(mSavedDepthStencil);
816 SafeRelease(mSavedDepthStencil);
817
818 device->SetRenderTarget(0, mSavedRenderTarget);
819 SafeRelease(mSavedRenderTarget);
820
821 ASSERT(mSavedStateBlock != nullptr);
822
823 if (mSavedStateBlock != nullptr)
824 {
825 mSavedStateBlock->Apply();
826 }
827 }
828
829 }
830