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.
7 // Blit9.cpp: Surface copy utility class.
9 #include "libGLESv2/renderer/d3d/d3d9/Blit9.h"
10 #include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h"
11 #include "libGLESv2/renderer/d3d/d3d9/formatutils9.h"
12 #include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h"
13 #include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h"
14 #include "libGLESv2/renderer/d3d/d3d9/Renderer9.h"
15 #include "libGLESv2/Framebuffer.h"
16 #include "libGLESv2/FramebufferAttachment.h"
17 #include "libGLESv2/main.h"
21 // Precompiled shaders
22 #include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/standardvs.h"
23 #include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/flipyvs.h"
24 #include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/passthroughps.h"
25 #include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/luminanceps.h"
26 #include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h"
28 const BYTE* const g_shaderCode[] =
34 g_ps20_componentmaskps
37 const size_t g_shaderSize[] =
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)
50 Blit9::Blit9(rx::Renderer9 *renderer)
51 : mRenderer(renderer),
52 mGeometryLoaded(false),
53 mQuadVertexBuffer(NULL),
54 mQuadVertexDeclaration(NULL),
55 mSavedStateBlock(NULL),
56 mSavedRenderTarget(NULL),
57 mSavedDepthStencil(NULL)
59 memset(mCompiledShaders, 0, sizeof(mCompiledShaders));
64 SafeRelease(mSavedStateBlock);
65 SafeRelease(mQuadVertexBuffer);
66 SafeRelease(mQuadVertexDeclaration);
68 for (int i = 0; i < SHADER_COUNT; i++)
70 SafeRelease(mCompiledShaders[i]);
74 gl::Error Blit9::initialize()
78 return gl::Error(GL_NO_ERROR);
81 static const float quad[] =
89 IDirect3DDevice9 *device = mRenderer->getDevice();
91 HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mQuadVertexBuffer, NULL);
95 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
96 return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal blit vertex shader, result: 0x%X.", result);
100 result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0);
102 if (FAILED(result) || lockPtr == NULL)
104 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
105 SafeRelease(mQuadVertexBuffer);
106 return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal blit vertex shader, result: 0x%X.", result);
109 memcpy(lockPtr, quad, sizeof(quad));
110 mQuadVertexBuffer->Unlock();
112 static const D3DVERTEXELEMENT9 elements[] =
114 { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
118 result = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration);
122 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
123 SafeRelease(mQuadVertexBuffer);
124 return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal blit vertex declaration, result: 0x%X.", result);
127 mGeometryLoaded = true;
128 return gl::Error(GL_NO_ERROR);
131 template <class D3DShaderType>
132 gl::Error Blit9::setShader(ShaderId source, const char *profile,
133 gl::Error (Renderer9::*createShader)(const DWORD *, size_t length, D3DShaderType **outShader),
134 HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*))
136 IDirect3DDevice9 *device = mRenderer->getDevice();
138 D3DShaderType *shader;
140 if (mCompiledShaders[source] != NULL)
142 shader = static_cast<D3DShaderType*>(mCompiledShaders[source]);
146 const BYTE* shaderCode = g_shaderCode[source];
147 size_t shaderSize = g_shaderSize[source];
149 gl::Error error = (mRenderer->*createShader)(reinterpret_cast<const DWORD*>(shaderCode), shaderSize, &shader);
155 mCompiledShaders[source] = shader;
158 HRESULT hr = (device->*setShader)(shader);
161 return gl::Error(GL_OUT_OF_MEMORY, "Failed to set shader for blit operation, result: 0x%X.", hr);
164 return gl::Error(GL_NO_ERROR);
167 gl::Error Blit9::setVertexShader(ShaderId shader)
169 return setShader<IDirect3DVertexShader9>(shader, "vs_2_0", &rx::Renderer9::createVertexShader, &IDirect3DDevice9::SetVertexShader);
172 gl::Error Blit9::setPixelShader(ShaderId shader)
174 return setShader<IDirect3DPixelShader9>(shader, "ps_2_0", &rx::Renderer9::createPixelShader, &IDirect3DDevice9::SetPixelShader);
177 RECT Blit9::getSurfaceRect(IDirect3DSurface9 *surface) const
179 D3DSURFACE_DESC desc;
180 surface->GetDesc(&desc);
185 rect.right = desc.Width;
186 rect.bottom = desc.Height;
191 gl::Error Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest)
193 gl::Error error = initialize();
199 IDirect3DTexture9 *texture = NULL;
200 error = copySurfaceToTexture(source, getSurfaceRect(source), &texture);
206 IDirect3DDevice9 *device = mRenderer->getDevice();
210 device->SetTexture(0, texture);
211 device->SetRenderTarget(0, dest);
213 setVertexShader(SHADER_VS_STANDARD);
214 setPixelShader(SHADER_PS_PASSTHROUGH);
216 setCommonBlitState();
217 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
218 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
220 setViewport(getSurfaceRect(dest), 0, 0);
224 SafeRelease(texture);
228 return gl::Error(GL_NO_ERROR);
231 gl::Error Blit9::copy2D(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level)
233 gl::Error error = initialize();
239 gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0);
242 RenderTarget9 *renderTarget9 = NULL;
243 error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget9);
248 ASSERT(renderTarget9);
250 IDirect3DSurface9 *source = renderTarget9->getSurface();
253 IDirect3DSurface9 *destSurface = NULL;
254 TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage);
255 error = storage9->getSurfaceLevel(level, true, &destSurface);
262 gl::Error result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface);
264 SafeRelease(destSurface);
270 gl::Error Blit9::copyCube(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level)
272 gl::Error error = initialize();
278 gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0);
281 RenderTarget9 *renderTarget9 = NULL;
282 error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget9);
287 ASSERT(renderTarget9);
289 IDirect3DSurface9 *source = renderTarget9->getSurface();
292 IDirect3DSurface9 *destSurface = NULL;
293 TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage);
294 error = storage9->getCubeMapSurface(target, level, true, &destSurface);
301 gl::Error result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface);
303 SafeRelease(destSurface);
309 gl::Error Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
311 ASSERT(source != NULL && dest != NULL);
313 IDirect3DDevice9 *device = mRenderer->getDevice();
315 D3DSURFACE_DESC sourceDesc;
316 D3DSURFACE_DESC destDesc;
317 source->GetDesc(&sourceDesc);
318 dest->GetDesc(&destDesc);
320 if (sourceDesc.Format == destDesc.Format && destDesc.Usage & D3DUSAGE_RENDERTARGET &&
321 d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat)) // Can use StretchRect
323 RECT destRect = {xoffset, yoffset, xoffset + (sourceRect.right - sourceRect.left), yoffset + (sourceRect.bottom - sourceRect.top)};
324 HRESULT result = device->StretchRect(source, &sourceRect, dest, &destRect, D3DTEXF_POINT);
328 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
329 return gl::Error(GL_OUT_OF_MEMORY, "Failed to blit between textures, StretchRect result: 0x%X.", result);
332 return gl::Error(GL_NO_ERROR);
336 return formatConvert(source, sourceRect, destFormat, xoffset, yoffset, dest);
340 gl::Error Blit9::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
342 gl::Error error = initialize();
348 IDirect3DTexture9 *texture = NULL;
349 error = copySurfaceToTexture(source, sourceRect, &texture);
355 IDirect3DDevice9 *device = mRenderer->getDevice();
359 device->SetTexture(0, texture);
360 device->SetRenderTarget(0, dest);
362 setViewport(sourceRect, xoffset, yoffset);
364 setCommonBlitState();
366 error = setFormatConvertShaders(destFormat);
367 if (!error.isError())
372 SafeRelease(texture);
379 gl::Error Blit9::setFormatConvertShaders(GLenum destFormat)
381 gl::Error error = setVertexShader(SHADER_VS_STANDARD);
389 default: UNREACHABLE();
396 error = setPixelShader(SHADER_PS_COMPONENTMASK);
400 case GL_LUMINANCE_ALPHA:
401 error = setPixelShader(SHADER_PS_LUMINANCE);
410 enum { X = 0, Y = 1, Z = 2, W = 3 };
412 // The meaning of this constant depends on the shader that was selected.
413 // See the shader assembly code above for details.
414 // Allocate one array for both registers and split it into two float4's.
415 float psConst[8] = { 0 };
416 float *multConst = &psConst[0];
417 float *addConst = &psConst[4];
421 default: UNREACHABLE();
489 case GL_LUMINANCE_ALPHA:
501 mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst, 2);
503 return gl::Error(GL_NO_ERROR);
506 gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect, IDirect3DTexture9 **outTexture)
510 IDirect3DDevice9 *device = mRenderer->getDevice();
512 D3DSURFACE_DESC sourceDesc;
513 surface->GetDesc(&sourceDesc);
515 // Copy the render target into a texture
516 IDirect3DTexture9 *texture;
517 HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1, D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, NULL);
521 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
522 return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal texture for blit, result: 0x%X.", result);
525 IDirect3DSurface9 *textureSurface;
526 result = texture->GetSurfaceLevel(0, &textureSurface);
530 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
531 SafeRelease(texture);
532 return gl::Error(GL_OUT_OF_MEMORY, "Failed to query surface of internal blit texture, result: 0x%X.", result);
535 mRenderer->endScene();
536 result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE);
538 SafeRelease(textureSurface);
542 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
543 SafeRelease(texture);
544 return gl::Error(GL_OUT_OF_MEMORY, "Failed to copy between internal blit textures, result: 0x%X.", result);
547 *outTexture = texture;
548 return gl::Error(GL_NO_ERROR);
551 void Blit9::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset)
553 IDirect3DDevice9 *device = mRenderer->getDevice();
558 vp.Width = sourceRect.right - sourceRect.left;
559 vp.Height = sourceRect.bottom - sourceRect.top;
562 device->SetViewport(&vp);
564 float halfPixelAdjust[4] = { -1.0f/vp.Width, 1.0f/vp.Height, 0, 0 };
565 device->SetVertexShaderConstantF(0, halfPixelAdjust, 1);
568 void Blit9::setCommonBlitState()
570 IDirect3DDevice9 *device = mRenderer->getDevice();
572 device->SetDepthStencilSurface(NULL);
574 device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
575 device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
576 device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
577 device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
578 device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
579 device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
580 device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
581 device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
583 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
584 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
585 device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE);
586 device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
587 device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
589 RECT scissorRect = {0}; // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle
590 device->SetScissorRect(&scissorRect);
592 for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
594 device->SetStreamSourceFreq(i, 1);
600 IDirect3DDevice9 *device = mRenderer->getDevice();
602 HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float));
603 hr = device->SetVertexDeclaration(mQuadVertexDeclaration);
605 mRenderer->startScene();
606 hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
609 void Blit9::saveState()
611 IDirect3DDevice9 *device = mRenderer->getDevice();
615 device->GetDepthStencilSurface(&mSavedDepthStencil);
616 device->GetRenderTarget(0, &mSavedRenderTarget);
618 if (mSavedStateBlock == NULL)
620 hr = device->BeginStateBlock();
621 ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
623 setCommonBlitState();
625 static const float dummyConst[8] = { 0 };
627 device->SetVertexShader(NULL);
628 device->SetVertexShaderConstantF(0, dummyConst, 2);
629 device->SetPixelShader(NULL);
630 device->SetPixelShaderConstantF(0, dummyConst, 2);
632 D3DVIEWPORT9 dummyVp;
640 device->SetViewport(&dummyVp);
642 device->SetTexture(0, NULL);
644 device->SetStreamSource(0, mQuadVertexBuffer, 0, 0);
646 device->SetVertexDeclaration(mQuadVertexDeclaration);
648 hr = device->EndStateBlock(&mSavedStateBlock);
649 ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
652 ASSERT(mSavedStateBlock != NULL);
654 if (mSavedStateBlock != NULL)
656 hr = mSavedStateBlock->Capture();
657 ASSERT(SUCCEEDED(hr));
661 void Blit9::restoreState()
663 IDirect3DDevice9 *device = mRenderer->getDevice();
665 device->SetDepthStencilSurface(mSavedDepthStencil);
666 SafeRelease(mSavedDepthStencil);
668 device->SetRenderTarget(0, mSavedRenderTarget);
669 SafeRelease(mSavedRenderTarget);
671 ASSERT(mSavedStateBlock != NULL);
673 if (mSavedStateBlock != NULL)
675 mSavedStateBlock->Apply();