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