• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "precompiled.h"
2 //
3 // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6 //
7 
8 // Blit.cpp: Surface copy utility class.
9 
10 #include "libGLESv2/renderer/Blit.h"
11 
12 #include "libGLESv2/main.h"
13 #include "libGLESv2/renderer/renderer9_utils.h"
14 #include "libGLESv2/renderer/TextureStorage9.h"
15 #include "libGLESv2/renderer/RenderTarget9.h"
16 #include "libGLESv2/renderer/Renderer9.h"
17 #include "libGLESv2/Framebuffer.h"
18 #include "libGLESv2/Renderbuffer.h"
19 
20 namespace
21 {
22 #include "libGLESv2/renderer/shaders/compiled/standardvs.h"
23 #include "libGLESv2/renderer/shaders/compiled/flipyvs.h"
24 #include "libGLESv2/renderer/shaders/compiled/passthroughps.h"
25 #include "libGLESv2/renderer/shaders/compiled/luminanceps.h"
26 #include "libGLESv2/renderer/shaders/compiled/componentmaskps.h"
27 
28 const BYTE* const g_shaderCode[] =
29 {
30     g_vs20_standardvs,
31     g_vs20_flipyvs,
32     g_ps20_passthroughps,
33     g_ps20_luminanceps,
34     g_ps20_componentmaskps
35 };
36 
37 const size_t g_shaderSize[] =
38 {
39     sizeof(g_vs20_standardvs),
40     sizeof(g_vs20_flipyvs),
41     sizeof(g_ps20_passthroughps),
42     sizeof(g_ps20_luminanceps),
43     sizeof(g_ps20_componentmaskps)
44 };
45 }
46 
47 namespace rx
48 {
Blit(rx::Renderer9 * renderer)49 Blit::Blit(rx::Renderer9 *renderer)
50   : mRenderer(renderer), mQuadVertexBuffer(NULL), mQuadVertexDeclaration(NULL), mSavedStateBlock(NULL), mSavedRenderTarget(NULL), mSavedDepthStencil(NULL)
51 {
52     initGeometry();
53     memset(mCompiledShaders, 0, sizeof(mCompiledShaders));
54 }
55 
~Blit()56 Blit::~Blit()
57 {
58     if (mSavedStateBlock) mSavedStateBlock->Release();
59     if (mQuadVertexBuffer) mQuadVertexBuffer->Release();
60     if (mQuadVertexDeclaration) mQuadVertexDeclaration->Release();
61 
62     for (int i = 0; i < SHADER_COUNT; i++)
63     {
64         if (mCompiledShaders[i])
65         {
66             mCompiledShaders[i]->Release();
67         }
68     }
69 }
70 
initGeometry()71 void Blit::initGeometry()
72 {
73     static const float quad[] =
74     {
75         -1, -1,
76         -1,  1,
77          1, -1,
78          1,  1
79     };
80 
81     IDirect3DDevice9 *device = mRenderer->getDevice();
82 
83     HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mQuadVertexBuffer, NULL);
84 
85     if (FAILED(result))
86     {
87         ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
88         return gl::error(GL_OUT_OF_MEMORY);
89     }
90 
91     void *lockPtr = NULL;
92     result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0);
93 
94     if (FAILED(result) || lockPtr == NULL)
95     {
96         ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
97         return gl::error(GL_OUT_OF_MEMORY);
98     }
99 
100     memcpy(lockPtr, quad, sizeof(quad));
101     mQuadVertexBuffer->Unlock();
102 
103     static const D3DVERTEXELEMENT9 elements[] =
104     {
105         { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
106         D3DDECL_END()
107     };
108 
109     result = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration);
110 
111     if (FAILED(result))
112     {
113         ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
114         return gl::error(GL_OUT_OF_MEMORY);
115     }
116 }
117 
118 template <class D3DShaderType>
setShader(ShaderId source,const char * profile,D3DShaderType * (rx::Renderer9::* createShader)(const DWORD *,size_t length),HRESULT (WINAPI IDirect3DDevice9::* setShader)(D3DShaderType *))119 bool Blit::setShader(ShaderId source, const char *profile,
120                      D3DShaderType *(rx::Renderer9::*createShader)(const DWORD *, size_t length),
121                      HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*))
122 {
123     IDirect3DDevice9 *device = mRenderer->getDevice();
124 
125     D3DShaderType *shader;
126 
127     if (mCompiledShaders[source] != NULL)
128     {
129         shader = static_cast<D3DShaderType*>(mCompiledShaders[source]);
130     }
131     else
132     {
133         const BYTE* shaderCode = g_shaderCode[source];
134         size_t shaderSize = g_shaderSize[source];
135 
136         shader = (mRenderer->*createShader)(reinterpret_cast<const DWORD*>(shaderCode), shaderSize);
137         if (!shader)
138         {
139             ERR("Failed to create shader for blit operation");
140             return false;
141         }
142 
143         mCompiledShaders[source] = shader;
144     }
145 
146     HRESULT hr = (device->*setShader)(shader);
147 
148     if (FAILED(hr))
149     {
150         ERR("Failed to set shader for blit operation");
151         return false;
152     }
153 
154     return true;
155 }
156 
setVertexShader(ShaderId shader)157 bool Blit::setVertexShader(ShaderId shader)
158 {
159     return setShader<IDirect3DVertexShader9>(shader, "vs_2_0", &rx::Renderer9::createVertexShader, &IDirect3DDevice9::SetVertexShader);
160 }
161 
setPixelShader(ShaderId shader)162 bool Blit::setPixelShader(ShaderId shader)
163 {
164     return setShader<IDirect3DPixelShader9>(shader, "ps_2_0", &rx::Renderer9::createPixelShader, &IDirect3DDevice9::SetPixelShader);
165 }
166 
getSurfaceRect(IDirect3DSurface9 * surface) const167 RECT Blit::getSurfaceRect(IDirect3DSurface9 *surface) const
168 {
169     D3DSURFACE_DESC desc;
170     surface->GetDesc(&desc);
171 
172     RECT rect;
173     rect.left = 0;
174     rect.top = 0;
175     rect.right = desc.Width;
176     rect.bottom = desc.Height;
177 
178     return rect;
179 }
180 
boxFilter(IDirect3DSurface9 * source,IDirect3DSurface9 * dest)181 bool Blit::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest)
182 {
183     IDirect3DTexture9 *texture = copySurfaceToTexture(source, getSurfaceRect(source));
184     if (!texture)
185     {
186         return false;
187     }
188 
189     IDirect3DDevice9 *device = mRenderer->getDevice();
190 
191     saveState();
192 
193     device->SetTexture(0, texture);
194     device->SetRenderTarget(0, dest);
195 
196     setVertexShader(SHADER_VS_STANDARD);
197     setPixelShader(SHADER_PS_PASSTHROUGH);
198 
199     setCommonBlitState();
200     device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
201     device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
202 
203     setViewport(getSurfaceRect(dest), 0, 0);
204 
205     render();
206 
207     texture->Release();
208 
209     restoreState();
210 
211     return true;
212 }
213 
copy(gl::Framebuffer * framebuffer,const RECT & sourceRect,GLenum destFormat,GLint xoffset,GLint yoffset,TextureStorageInterface2D * storage,GLint level)214 bool Blit::copy(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level)
215 {
216     RenderTarget9 *renderTarget = NULL;
217     IDirect3DSurface9 *source = NULL;
218     gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(0);
219 
220     if (colorbuffer)
221     {
222         renderTarget = RenderTarget9::makeRenderTarget9(colorbuffer->getRenderTarget());
223     }
224 
225     if (renderTarget)
226     {
227         source = renderTarget->getSurface();
228     }
229 
230     if (!source)
231     {
232         ERR("Failed to retrieve the render target.");
233         return gl::error(GL_OUT_OF_MEMORY, false);
234     }
235 
236     TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage->getStorageInstance());
237     IDirect3DSurface9 *destSurface = storage9->getSurfaceLevel(level, true);
238     bool result = false;
239 
240     if (destSurface)
241     {
242         result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface);
243         destSurface->Release();
244     }
245 
246     source->Release();
247     return result;
248 }
249 
copy(gl::Framebuffer * framebuffer,const RECT & sourceRect,GLenum destFormat,GLint xoffset,GLint yoffset,TextureStorageInterfaceCube * storage,GLenum target,GLint level)250 bool Blit::copy(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level)
251 {
252     RenderTarget9 *renderTarget = NULL;
253     IDirect3DSurface9 *source = NULL;
254     gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(0);
255 
256     if (colorbuffer)
257     {
258         renderTarget = RenderTarget9::makeRenderTarget9(colorbuffer->getRenderTarget());
259     }
260 
261     if (renderTarget)
262     {
263         source = renderTarget->getSurface();
264     }
265 
266     if (!source)
267     {
268         ERR("Failed to retrieve the render target.");
269         return gl::error(GL_OUT_OF_MEMORY, false);
270     }
271 
272     TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage->getStorageInstance());
273     IDirect3DSurface9 *destSurface = storage9->getCubeMapSurface(target, level, true);
274     bool result = false;
275 
276     if (destSurface)
277     {
278         result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface);
279         destSurface->Release();
280     }
281 
282     source->Release();
283     return result;
284 }
285 
copy(IDirect3DSurface9 * source,const RECT & sourceRect,GLenum destFormat,GLint xoffset,GLint yoffset,IDirect3DSurface9 * dest)286 bool Blit::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
287 {
288     if (!dest)
289     {
290         return false;
291     }
292 
293     IDirect3DDevice9 *device = mRenderer->getDevice();
294 
295     D3DSURFACE_DESC sourceDesc;
296     D3DSURFACE_DESC destDesc;
297     source->GetDesc(&sourceDesc);
298     dest->GetDesc(&destDesc);
299 
300     if (sourceDesc.Format == destDesc.Format && destDesc.Usage & D3DUSAGE_RENDERTARGET &&
301         d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat))   // Can use StretchRect
302     {
303         RECT destRect = {xoffset, yoffset, xoffset + (sourceRect.right - sourceRect.left), yoffset + (sourceRect.bottom - sourceRect.top)};
304         HRESULT result = device->StretchRect(source, &sourceRect, dest, &destRect, D3DTEXF_POINT);
305 
306         if (FAILED(result))
307         {
308             ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
309             return gl::error(GL_OUT_OF_MEMORY, false);
310         }
311     }
312     else
313     {
314         return formatConvert(source, sourceRect, destFormat, xoffset, yoffset, dest);
315     }
316     return true;
317 }
318 
formatConvert(IDirect3DSurface9 * source,const RECT & sourceRect,GLenum destFormat,GLint xoffset,GLint yoffset,IDirect3DSurface9 * dest)319 bool Blit::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
320 {
321     IDirect3DTexture9 *texture = copySurfaceToTexture(source, sourceRect);
322     if (!texture)
323     {
324         return false;
325     }
326 
327     IDirect3DDevice9 *device = mRenderer->getDevice();
328 
329     saveState();
330 
331     device->SetTexture(0, texture);
332     device->SetRenderTarget(0, dest);
333 
334     setViewport(sourceRect, xoffset, yoffset);
335 
336     setCommonBlitState();
337     if (setFormatConvertShaders(destFormat))
338     {
339         render();
340     }
341 
342     texture->Release();
343 
344     restoreState();
345 
346     return true;
347 }
348 
setFormatConvertShaders(GLenum destFormat)349 bool Blit::setFormatConvertShaders(GLenum destFormat)
350 {
351     bool okay = setVertexShader(SHADER_VS_STANDARD);
352 
353     switch (destFormat)
354     {
355       default: UNREACHABLE();
356       case GL_RGBA:
357       case GL_BGRA_EXT:
358       case GL_RGB:
359       case GL_ALPHA:
360         okay = okay && setPixelShader(SHADER_PS_COMPONENTMASK);
361         break;
362 
363       case GL_LUMINANCE:
364       case GL_LUMINANCE_ALPHA:
365         okay = okay && setPixelShader(SHADER_PS_LUMINANCE);
366         break;
367     }
368 
369     if (!okay)
370     {
371         return false;
372     }
373 
374     enum { X = 0, Y = 1, Z = 2, W = 3 };
375 
376     // The meaning of this constant depends on the shader that was selected.
377     // See the shader assembly code above for details.
378     float psConst0[4] = { 0, 0, 0, 0 };
379 
380     switch (destFormat)
381     {
382       default: UNREACHABLE();
383       case GL_RGBA:
384       case GL_BGRA_EXT:
385         psConst0[X] = 1;
386         psConst0[Z] = 1;
387         break;
388 
389       case GL_RGB:
390         psConst0[X] = 1;
391         psConst0[W] = 1;
392         break;
393 
394       case GL_ALPHA:
395         psConst0[Z] = 1;
396         break;
397 
398       case GL_LUMINANCE:
399         psConst0[Y] = 1;
400         break;
401 
402       case GL_LUMINANCE_ALPHA:
403         psConst0[X] = 1;
404         break;
405     }
406 
407     mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst0, 1);
408 
409     return true;
410 }
411 
copySurfaceToTexture(IDirect3DSurface9 * surface,const RECT & sourceRect)412 IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect)
413 {
414     if (!surface)
415     {
416         return NULL;
417     }
418 
419     IDirect3DDevice9 *device = mRenderer->getDevice();
420 
421     D3DSURFACE_DESC sourceDesc;
422     surface->GetDesc(&sourceDesc);
423 
424     // Copy the render target into a texture
425     IDirect3DTexture9 *texture;
426     HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1, D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, NULL);
427 
428     if (FAILED(result))
429     {
430         ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
431         return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
432     }
433 
434     IDirect3DSurface9 *textureSurface;
435     result = texture->GetSurfaceLevel(0, &textureSurface);
436 
437     if (FAILED(result))
438     {
439         ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
440         texture->Release();
441         return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
442     }
443 
444     mRenderer->endScene();
445     result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE);
446 
447     textureSurface->Release();
448 
449     if (FAILED(result))
450     {
451         ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
452         texture->Release();
453         return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
454     }
455 
456     return texture;
457 }
458 
setViewport(const RECT & sourceRect,GLint xoffset,GLint yoffset)459 void Blit::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset)
460 {
461     IDirect3DDevice9 *device = mRenderer->getDevice();
462 
463     D3DVIEWPORT9 vp;
464     vp.X      = xoffset;
465     vp.Y      = yoffset;
466     vp.Width  = sourceRect.right - sourceRect.left;
467     vp.Height = sourceRect.bottom - sourceRect.top;
468     vp.MinZ   = 0.0f;
469     vp.MaxZ   = 1.0f;
470     device->SetViewport(&vp);
471 
472     float halfPixelAdjust[4] = { -1.0f/vp.Width, 1.0f/vp.Height, 0, 0 };
473     device->SetVertexShaderConstantF(0, halfPixelAdjust, 1);
474 }
475 
setCommonBlitState()476 void Blit::setCommonBlitState()
477 {
478     IDirect3DDevice9 *device = mRenderer->getDevice();
479 
480     device->SetDepthStencilSurface(NULL);
481 
482     device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
483     device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
484     device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
485     device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
486     device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
487     device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
488     device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
489     device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
490 
491     device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
492     device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
493     device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE);
494     device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
495     device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
496 
497     RECT scissorRect = {0};   // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle
498     device->SetScissorRect(&scissorRect);
499 
500     for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
501     {
502         device->SetStreamSourceFreq(i, 1);
503     }
504 }
505 
render()506 void Blit::render()
507 {
508     IDirect3DDevice9 *device = mRenderer->getDevice();
509 
510     HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float));
511     hr = device->SetVertexDeclaration(mQuadVertexDeclaration);
512 
513     mRenderer->startScene();
514     hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
515 }
516 
saveState()517 void Blit::saveState()
518 {
519     IDirect3DDevice9 *device = mRenderer->getDevice();
520 
521     HRESULT hr;
522 
523     device->GetDepthStencilSurface(&mSavedDepthStencil);
524     device->GetRenderTarget(0, &mSavedRenderTarget);
525 
526     if (mSavedStateBlock == NULL)
527     {
528         hr = device->BeginStateBlock();
529         ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
530 
531         setCommonBlitState();
532 
533         static const float dummyConst[4] = { 0, 0, 0, 0 };
534 
535         device->SetVertexShader(NULL);
536         device->SetVertexShaderConstantF(0, dummyConst, 1);
537         device->SetPixelShader(NULL);
538         device->SetPixelShaderConstantF(0, dummyConst, 1);
539 
540         D3DVIEWPORT9 dummyVp;
541         dummyVp.X = 0;
542         dummyVp.Y = 0;
543         dummyVp.Width = 1;
544         dummyVp.Height = 1;
545         dummyVp.MinZ = 0;
546         dummyVp.MaxZ = 1;
547 
548         device->SetViewport(&dummyVp);
549 
550         device->SetTexture(0, NULL);
551 
552         device->SetStreamSource(0, mQuadVertexBuffer, 0, 0);
553 
554         device->SetVertexDeclaration(mQuadVertexDeclaration);
555 
556         hr = device->EndStateBlock(&mSavedStateBlock);
557         ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
558     }
559 
560     ASSERT(mSavedStateBlock != NULL);
561 
562     if (mSavedStateBlock != NULL)
563     {
564         hr = mSavedStateBlock->Capture();
565         ASSERT(SUCCEEDED(hr));
566     }
567 }
568 
restoreState()569 void Blit::restoreState()
570 {
571     IDirect3DDevice9 *device = mRenderer->getDevice();
572 
573     device->SetDepthStencilSurface(mSavedDepthStencil);
574     if (mSavedDepthStencil != NULL)
575     {
576         mSavedDepthStencil->Release();
577         mSavedDepthStencil = NULL;
578     }
579 
580     device->SetRenderTarget(0, mSavedRenderTarget);
581     if (mSavedRenderTarget != NULL)
582     {
583         mSavedRenderTarget->Release();
584         mSavedRenderTarget = NULL;
585     }
586 
587     ASSERT(mSavedStateBlock != NULL);
588 
589     if (mSavedStateBlock != NULL)
590     {
591         mSavedStateBlock->Apply();
592     }
593 }
594 
595 }
596