summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp')
-rw-r--r--gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp760
1 files changed, 760 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp
new file mode 100644
index 0000000000..429159b4cb
--- /dev/null
+++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp
@@ -0,0 +1,760 @@
+//
+// Copyright 2002 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Blit9.cpp: Surface copy utility class.
+
+#include "libANGLE/renderer/d3d/d3d9/Blit9.h"
+
+#include "libANGLE/Context.h"
+#include "libANGLE/Framebuffer.h"
+#include "libANGLE/FramebufferAttachment.h"
+#include "libANGLE/angletypes.h"
+#include "libANGLE/renderer/d3d/TextureD3D.h"
+#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h"
+#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
+#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
+
+namespace
+{
+// Precompiled shaders
+#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskpremultps.h"
+#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h"
+#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskunmultps.h"
+#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminancepremultps.h"
+#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceps.h"
+#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceunmultps.h"
+#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/passthroughps.h"
+#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/standardvs.h"
+
+const BYTE *const g_shaderCode[] = {
+ g_vs20_standardvs,
+ g_ps20_passthroughps,
+ g_ps20_luminanceps,
+ g_ps20_luminancepremultps,
+ g_ps20_luminanceunmultps,
+ g_ps20_componentmaskps,
+ g_ps20_componentmaskpremultps,
+ g_ps20_componentmaskunmultps,
+};
+
+const size_t g_shaderSize[] = {
+ sizeof(g_vs20_standardvs),
+ sizeof(g_ps20_passthroughps),
+ sizeof(g_ps20_luminanceps),
+ sizeof(g_ps20_luminancepremultps),
+ sizeof(g_ps20_luminanceunmultps),
+ sizeof(g_ps20_componentmaskps),
+ sizeof(g_ps20_componentmaskpremultps),
+ sizeof(g_ps20_componentmaskunmultps),
+};
+} // namespace
+
+namespace rx
+{
+
+Blit9::Blit9(Renderer9 *renderer)
+ : mRenderer(renderer),
+ mGeometryLoaded(false),
+ mQuadVertexBuffer(nullptr),
+ mQuadVertexDeclaration(nullptr),
+ mSavedStateBlock(nullptr),
+ mSavedRenderTarget(nullptr),
+ mSavedDepthStencil(nullptr)
+{
+ memset(mCompiledShaders, 0, sizeof(mCompiledShaders));
+}
+
+Blit9::~Blit9()
+{
+ SafeRelease(mSavedStateBlock);
+ SafeRelease(mQuadVertexBuffer);
+ SafeRelease(mQuadVertexDeclaration);
+
+ for (int i = 0; i < SHADER_COUNT; i++)
+ {
+ SafeRelease(mCompiledShaders[i]);
+ }
+}
+
+angle::Result Blit9::initialize(Context9 *context9)
+{
+ if (mGeometryLoaded)
+ {
+ return angle::Result::Continue;
+ }
+
+ static const float quad[] = {-1, -1, -1, 1, 1, -1, 1, 1};
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0,
+ D3DPOOL_DEFAULT, &mQuadVertexBuffer, nullptr);
+
+ ANGLE_TRY_HR(context9, result, "Failed to create internal blit vertex shader");
+
+ void *lockPtr = nullptr;
+ result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0);
+
+ ANGLE_TRY_HR(context9, result, "Failed to lock internal blit vertex shader");
+ ASSERT(lockPtr);
+
+ memcpy(lockPtr, quad, sizeof(quad));
+ mQuadVertexBuffer->Unlock();
+
+ static const D3DVERTEXELEMENT9 elements[] = {
+ {0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, D3DDECL_END()};
+
+ result = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration);
+ ANGLE_TRY_HR(context9, result, "Failed to create internal blit vertex shader declaration");
+
+ mGeometryLoaded = true;
+ return angle::Result::Continue;
+}
+
+template <class D3DShaderType>
+angle::Result Blit9::setShader(Context9 *context9,
+ ShaderId source,
+ const char *profile,
+ angle::Result (Renderer9::*createShader)(d3d::Context *,
+ const DWORD *,
+ size_t length,
+ D3DShaderType **outShader),
+ HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType *))
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ D3DShaderType *shader = nullptr;
+
+ if (mCompiledShaders[source] != nullptr)
+ {
+ shader = static_cast<D3DShaderType *>(mCompiledShaders[source]);
+ }
+ else
+ {
+ const BYTE *shaderCode = g_shaderCode[source];
+ size_t shaderSize = g_shaderSize[source];
+ ANGLE_TRY((mRenderer->*createShader)(context9, reinterpret_cast<const DWORD *>(shaderCode),
+ shaderSize, &shader));
+ mCompiledShaders[source] = shader;
+ }
+
+ HRESULT hr = (device->*setShader)(shader);
+ ANGLE_TRY_HR(context9, hr, "Failed to set shader for blit operation");
+ return angle::Result::Continue;
+}
+
+angle::Result Blit9::setVertexShader(Context9 *context9, ShaderId shader)
+{
+ return setShader<IDirect3DVertexShader9>(context9, shader, "vs_2_0",
+ &Renderer9::createVertexShader,
+ &IDirect3DDevice9::SetVertexShader);
+}
+
+angle::Result Blit9::setPixelShader(Context9 *context9, ShaderId shader)
+{
+ return setShader<IDirect3DPixelShader9>(context9, shader, "ps_2_0",
+ &Renderer9::createPixelShader,
+ &IDirect3DDevice9::SetPixelShader);
+}
+
+RECT Blit9::getSurfaceRect(IDirect3DSurface9 *surface) const
+{
+ D3DSURFACE_DESC desc;
+ surface->GetDesc(&desc);
+
+ RECT rect;
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = desc.Width;
+ rect.bottom = desc.Height;
+
+ return rect;
+}
+
+gl::Extents Blit9::getSurfaceSize(IDirect3DSurface9 *surface) const
+{
+ D3DSURFACE_DESC desc;
+ surface->GetDesc(&desc);
+
+ return gl::Extents(desc.Width, desc.Height, 1);
+}
+
+angle::Result Blit9::boxFilter(Context9 *context9,
+ IDirect3DSurface9 *source,
+ IDirect3DSurface9 *dest)
+{
+ ANGLE_TRY(initialize(context9));
+
+ angle::ComPtr<IDirect3DBaseTexture9> texture = nullptr;
+ ANGLE_TRY(copySurfaceToTexture(context9, source, getSurfaceRect(source), &texture));
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ saveState();
+
+ device->SetTexture(0, texture.Get());
+ device->SetRenderTarget(0, dest);
+
+ ANGLE_TRY(setVertexShader(context9, SHADER_VS_STANDARD));
+ ANGLE_TRY(setPixelShader(context9, SHADER_PS_PASSTHROUGH));
+
+ setCommonBlitState();
+ device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+ device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+
+ setViewportAndShaderConstants(getSurfaceRect(source), getSurfaceSize(source),
+ getSurfaceRect(dest), false);
+
+ render();
+
+ restoreState();
+
+ return angle::Result::Continue;
+}
+
+angle::Result Blit9::copy2D(const gl::Context *context,
+ const gl::Framebuffer *framebuffer,
+ const RECT &sourceRect,
+ GLenum destFormat,
+ const gl::Offset &destOffset,
+ TextureStorage *storage,
+ GLint level)
+{
+ Context9 *context9 = GetImplAs<Context9>(context);
+
+ ANGLE_TRY(initialize(context9));
+
+ const gl::FramebufferAttachment *colorbuffer = framebuffer->getColorAttachment(0);
+ ASSERT(colorbuffer);
+
+ RenderTarget9 *renderTarget9 = nullptr;
+ ANGLE_TRY(colorbuffer->getRenderTarget(context, 0, &renderTarget9));
+ ASSERT(renderTarget9);
+
+ angle::ComPtr<IDirect3DSurface9> source = renderTarget9->getSurface();
+ ASSERT(source);
+
+ angle::ComPtr<IDirect3DSurface9> destSurface = nullptr;
+ TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
+ ANGLE_TRY(
+ storage9->getSurfaceLevel(context, gl::TextureTarget::_2D, level, true, &destSurface));
+ ASSERT(destSurface);
+
+ ANGLE_TRY(copy(context9, source.Get(), nullptr, sourceRect, destFormat, destOffset,
+ destSurface.Get(), false, false, false));
+ return angle::Result::Continue;
+}
+
+angle::Result Blit9::copyCube(const gl::Context *context,
+ const gl::Framebuffer *framebuffer,
+ const RECT &sourceRect,
+ GLenum destFormat,
+ const gl::Offset &destOffset,
+ TextureStorage *storage,
+ gl::TextureTarget target,
+ GLint level)
+{
+ Context9 *context9 = GetImplAs<Context9>(context);
+
+ ANGLE_TRY(initialize(context9));
+
+ const gl::FramebufferAttachment *colorbuffer = framebuffer->getColorAttachment(0);
+ ASSERT(colorbuffer);
+
+ RenderTarget9 *renderTarget9 = nullptr;
+ ANGLE_TRY(colorbuffer->getRenderTarget(context, 0, &renderTarget9));
+ ASSERT(renderTarget9);
+
+ angle::ComPtr<IDirect3DSurface9> source = renderTarget9->getSurface();
+ ASSERT(source);
+
+ angle::ComPtr<IDirect3DSurface9> destSurface = nullptr;
+ TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
+ ANGLE_TRY(storage9->getSurfaceLevel(context, target, level, true, &destSurface));
+ ASSERT(destSurface);
+
+ return copy(context9, source.Get(), nullptr, sourceRect, destFormat, destOffset,
+ destSurface.Get(), false, false, false);
+}
+
+angle::Result Blit9::copyTexture(const gl::Context *context,
+ const gl::Texture *source,
+ GLint sourceLevel,
+ const RECT &sourceRect,
+ GLenum destFormat,
+ const gl::Offset &destOffset,
+ TextureStorage *storage,
+ gl::TextureTarget destTarget,
+ GLint destLevel,
+ bool flipY,
+ bool premultiplyAlpha,
+ bool unmultiplyAlpha)
+{
+ Context9 *context9 = GetImplAs<Context9>(context);
+ ANGLE_TRY(initialize(context9));
+
+ TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
+
+ TextureStorage *sourceStorage = nullptr;
+ ANGLE_TRY(sourceD3D->getNativeTexture(context, &sourceStorage));
+
+ TextureStorage9_2D *sourceStorage9 = GetAs<TextureStorage9_2D>(sourceStorage);
+ ASSERT(sourceStorage9);
+
+ TextureStorage9 *destStorage9 = GetAs<TextureStorage9>(storage);
+ ASSERT(destStorage9);
+
+ ASSERT(sourceLevel == 0);
+ IDirect3DBaseTexture9 *sourceTexture = nullptr;
+ ANGLE_TRY(sourceStorage9->getBaseTexture(context, &sourceTexture));
+
+ angle::ComPtr<IDirect3DSurface9> sourceSurface = nullptr;
+ ANGLE_TRY(sourceStorage9->getSurfaceLevel(context, gl::TextureTarget::_2D, sourceLevel, true,
+ &sourceSurface));
+
+ angle::ComPtr<IDirect3DSurface9> destSurface = nullptr;
+ ANGLE_TRY(destStorage9->getSurfaceLevel(context, destTarget, destLevel, true, &destSurface));
+
+ return copy(context9, sourceSurface.Get(), sourceTexture, sourceRect, destFormat, destOffset,
+ destSurface.Get(), flipY, premultiplyAlpha, unmultiplyAlpha);
+}
+
+angle::Result Blit9::copy(Context9 *context9,
+ IDirect3DSurface9 *source,
+ IDirect3DBaseTexture9 *sourceTexture,
+ const RECT &sourceRect,
+ GLenum destFormat,
+ const gl::Offset &destOffset,
+ IDirect3DSurface9 *dest,
+ bool flipY,
+ bool premultiplyAlpha,
+ bool unmultiplyAlpha)
+{
+ ASSERT(source != nullptr && dest != nullptr);
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ D3DSURFACE_DESC sourceDesc;
+ D3DSURFACE_DESC destDesc;
+ source->GetDesc(&sourceDesc);
+ dest->GetDesc(&destDesc);
+
+ // Check if it's possible to use StetchRect
+ if (sourceDesc.Format == destDesc.Format && (destDesc.Usage & D3DUSAGE_RENDERTARGET) &&
+ d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat) && !flipY &&
+ premultiplyAlpha == unmultiplyAlpha)
+ {
+ RECT destRect = {destOffset.x, destOffset.y,
+ destOffset.x + (sourceRect.right - sourceRect.left),
+ destOffset.y + (sourceRect.bottom - sourceRect.top)};
+ HRESULT result = device->StretchRect(source, &sourceRect, dest, &destRect, D3DTEXF_POINT);
+ ANGLE_TRY_HR(context9, result, "StretchRect failed to blit between textures");
+ return angle::Result::Continue;
+ }
+
+ angle::ComPtr<IDirect3DBaseTexture9> texture = sourceTexture;
+ RECT adjustedSourceRect = sourceRect;
+ gl::Extents sourceSize(sourceDesc.Width, sourceDesc.Height, 1);
+
+ if (texture == nullptr)
+ {
+ ANGLE_TRY(copySurfaceToTexture(context9, source, sourceRect, &texture));
+
+ // copySurfaceToTexture only copies in the sourceRect area of the source surface.
+ // Adjust sourceRect so that it is now covering the entire source texture
+ adjustedSourceRect.left = 0;
+ adjustedSourceRect.right = sourceRect.right - sourceRect.left;
+ adjustedSourceRect.top = 0;
+ adjustedSourceRect.bottom = sourceRect.bottom - sourceRect.top;
+
+ sourceSize.width = sourceRect.right - sourceRect.left;
+ sourceSize.height = sourceRect.bottom - sourceRect.top;
+ }
+
+ ANGLE_TRY(formatConvert(context9, texture.Get(), adjustedSourceRect, sourceSize, destFormat,
+ destOffset, dest, flipY, premultiplyAlpha, unmultiplyAlpha));
+ return angle::Result::Continue;
+}
+
+angle::Result Blit9::formatConvert(Context9 *context9,
+ IDirect3DBaseTexture9 *source,
+ const RECT &sourceRect,
+ const gl::Extents &sourceSize,
+ GLenum destFormat,
+ const gl::Offset &destOffset,
+ IDirect3DSurface9 *dest,
+ bool flipY,
+ bool premultiplyAlpha,
+ bool unmultiplyAlpha)
+{
+ ANGLE_TRY(initialize(context9));
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ saveState();
+
+ device->SetTexture(0, source);
+ device->SetRenderTarget(0, dest);
+
+ RECT destRect;
+ destRect.left = destOffset.x;
+ destRect.right = destOffset.x + (sourceRect.right - sourceRect.left);
+ destRect.top = destOffset.y;
+ destRect.bottom = destOffset.y + (sourceRect.bottom - sourceRect.top);
+
+ setViewportAndShaderConstants(sourceRect, sourceSize, destRect, flipY);
+
+ setCommonBlitState();
+
+ angle::Result result =
+ setFormatConvertShaders(context9, destFormat, flipY, premultiplyAlpha, unmultiplyAlpha);
+ if (result == angle::Result::Continue)
+ {
+ render();
+ }
+
+ restoreState();
+
+ return result;
+}
+
+angle::Result Blit9::setFormatConvertShaders(Context9 *context9,
+ GLenum destFormat,
+ bool flipY,
+ bool premultiplyAlpha,
+ bool unmultiplyAlpha)
+{
+ ANGLE_TRY(setVertexShader(context9, SHADER_VS_STANDARD));
+
+ switch (destFormat)
+ {
+ case GL_RGBA:
+ case GL_BGRA_EXT:
+ case GL_RGB:
+ case GL_RG_EXT:
+ case GL_RED_EXT:
+ case GL_ALPHA:
+ if (premultiplyAlpha == unmultiplyAlpha)
+ {
+ ANGLE_TRY(setPixelShader(context9, SHADER_PS_COMPONENTMASK));
+ }
+ else if (premultiplyAlpha)
+ {
+ ANGLE_TRY(setPixelShader(context9, SHADER_PS_COMPONENTMASK_PREMULTIPLY_ALPHA));
+ }
+ else
+ {
+ ASSERT(unmultiplyAlpha);
+ ANGLE_TRY(setPixelShader(context9, SHADER_PS_COMPONENTMASK_UNMULTIPLY_ALPHA));
+ }
+ break;
+
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ if (premultiplyAlpha == unmultiplyAlpha)
+ {
+ ANGLE_TRY(setPixelShader(context9, SHADER_PS_LUMINANCE));
+ }
+ else if (premultiplyAlpha)
+ {
+ ANGLE_TRY(setPixelShader(context9, SHADER_PS_LUMINANCE_PREMULTIPLY_ALPHA));
+ }
+ else
+ {
+ ASSERT(unmultiplyAlpha);
+ ANGLE_TRY(setPixelShader(context9, SHADER_PS_LUMINANCE_UNMULTIPLY_ALPHA));
+ }
+ break;
+
+ default:
+ UNREACHABLE();
+ }
+
+ enum
+ {
+ X = 0,
+ Y = 1,
+ Z = 2,
+ W = 3
+ };
+
+ // The meaning of this constant depends on the shader that was selected.
+ // See the shader assembly code above for details.
+ // Allocate one array for both registers and split it into two float4's.
+ float psConst[8] = {0};
+ float *multConst = &psConst[0];
+ float *addConst = &psConst[4];
+
+ switch (destFormat)
+ {
+ case GL_RGBA:
+ case GL_BGRA_EXT:
+ multConst[X] = 1;
+ multConst[Y] = 1;
+ multConst[Z] = 1;
+ multConst[W] = 1;
+ addConst[X] = 0;
+ addConst[Y] = 0;
+ addConst[Z] = 0;
+ addConst[W] = 0;
+ break;
+
+ case GL_RGB:
+ multConst[X] = 1;
+ multConst[Y] = 1;
+ multConst[Z] = 1;
+ multConst[W] = 0;
+ addConst[X] = 0;
+ addConst[Y] = 0;
+ addConst[Z] = 0;
+ addConst[W] = 1;
+ break;
+
+ case GL_RG_EXT:
+ multConst[X] = 1;
+ multConst[Y] = 1;
+ multConst[Z] = 0;
+ multConst[W] = 0;
+ addConst[X] = 0;
+ addConst[Y] = 0;
+ addConst[Z] = 0;
+ addConst[W] = 1;
+ break;
+
+ case GL_RED_EXT:
+ multConst[X] = 1;
+ multConst[Y] = 0;
+ multConst[Z] = 0;
+ multConst[W] = 0;
+ addConst[X] = 0;
+ addConst[Y] = 0;
+ addConst[Z] = 0;
+ addConst[W] = 1;
+ break;
+
+ case GL_ALPHA:
+ multConst[X] = 0;
+ multConst[Y] = 0;
+ multConst[Z] = 0;
+ multConst[W] = 1;
+ addConst[X] = 0;
+ addConst[Y] = 0;
+ addConst[Z] = 0;
+ addConst[W] = 0;
+ break;
+
+ case GL_LUMINANCE:
+ multConst[X] = 1;
+ multConst[Y] = 0;
+ multConst[Z] = 0;
+ multConst[W] = 0;
+ addConst[X] = 0;
+ addConst[Y] = 0;
+ addConst[Z] = 0;
+ addConst[W] = 1;
+ break;
+
+ case GL_LUMINANCE_ALPHA:
+ multConst[X] = 1;
+ multConst[Y] = 0;
+ multConst[Z] = 0;
+ multConst[W] = 1;
+ addConst[X] = 0;
+ addConst[Y] = 0;
+ addConst[Z] = 0;
+ addConst[W] = 0;
+ break;
+
+ default:
+ UNREACHABLE();
+ }
+
+ mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst, 2);
+
+ return angle::Result::Continue;
+}
+
+angle::Result Blit9::copySurfaceToTexture(Context9 *context9,
+ IDirect3DSurface9 *surface,
+ const RECT &sourceRect,
+ angle::ComPtr<IDirect3DBaseTexture9> *outTexture)
+{
+ ASSERT(surface);
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ D3DSURFACE_DESC sourceDesc;
+ surface->GetDesc(&sourceDesc);
+
+ // Copy the render target into a texture
+ angle::ComPtr<IDirect3DTexture9> texture;
+ HRESULT result = device->CreateTexture(
+ sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1,
+ D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, nullptr);
+ ANGLE_TRY_HR(context9, result, "Failed to allocate internal texture for blit");
+
+ angle::ComPtr<IDirect3DSurface9> textureSurface;
+ result = texture->GetSurfaceLevel(0, &textureSurface);
+ ANGLE_TRY_HR(context9, result, "Failed to query surface of internal blit texture");
+
+ mRenderer->endScene();
+ result = device->StretchRect(surface, &sourceRect, textureSurface.Get(), nullptr, D3DTEXF_NONE);
+ ANGLE_TRY_HR(context9, result, "Failed to copy between internal blit textures");
+ *outTexture = texture;
+
+ return angle::Result::Continue;
+}
+
+void Blit9::setViewportAndShaderConstants(const RECT &sourceRect,
+ const gl::Extents &sourceSize,
+ const RECT &destRect,
+ bool flipY)
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ D3DVIEWPORT9 vp;
+ vp.X = destRect.left;
+ vp.Y = destRect.top;
+ vp.Width = destRect.right - destRect.left;
+ vp.Height = destRect.bottom - destRect.top;
+ vp.MinZ = 0.0f;
+ vp.MaxZ = 1.0f;
+ device->SetViewport(&vp);
+
+ float vertexConstants[8] = {
+ // halfPixelAdjust
+ -1.0f / vp.Width,
+ 1.0f / vp.Height,
+ 0,
+ 0,
+ // texcoordOffset
+ static_cast<float>(sourceRect.left) / sourceSize.width,
+ static_cast<float>(flipY ? sourceRect.bottom : sourceRect.top) / sourceSize.height,
+ static_cast<float>(sourceRect.right - sourceRect.left) / sourceSize.width,
+ static_cast<float>(flipY ? sourceRect.top - sourceRect.bottom
+ : sourceRect.bottom - sourceRect.top) /
+ sourceSize.height,
+ };
+
+ device->SetVertexShaderConstantF(0, vertexConstants, 2);
+}
+
+void Blit9::setCommonBlitState()
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ device->SetDepthStencilSurface(nullptr);
+
+ device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+ device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+ device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
+ device->SetRenderState(D3DRS_COLORWRITEENABLE,
+ D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE |
+ D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
+ device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
+ device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
+
+ device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
+ device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
+ device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE);
+ device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+ device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+
+ RECT scissorRect = {}; // Scissoring is disabled for flipping, but we need this to capture and
+ // restore the old rectangle
+ device->SetScissorRect(&scissorRect);
+
+ for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ device->SetStreamSourceFreq(i, 1);
+ }
+}
+
+void Blit9::render()
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float));
+ device->SetVertexDeclaration(mQuadVertexDeclaration);
+
+ mRenderer->startScene();
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
+}
+
+void Blit9::saveState()
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ HRESULT hr;
+
+ device->GetDepthStencilSurface(&mSavedDepthStencil);
+ device->GetRenderTarget(0, &mSavedRenderTarget);
+
+ if (mSavedStateBlock == nullptr)
+ {
+ hr = device->BeginStateBlock();
+ ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+
+ setCommonBlitState();
+
+ static const float mockConst[8] = {0};
+
+ device->SetVertexShader(nullptr);
+ device->SetVertexShaderConstantF(0, mockConst, 2);
+ device->SetPixelShader(nullptr);
+ device->SetPixelShaderConstantF(0, mockConst, 2);
+
+ D3DVIEWPORT9 mockVp;
+ mockVp.X = 0;
+ mockVp.Y = 0;
+ mockVp.Width = 1;
+ mockVp.Height = 1;
+ mockVp.MinZ = 0;
+ mockVp.MaxZ = 1;
+
+ device->SetViewport(&mockVp);
+
+ device->SetTexture(0, nullptr);
+
+ device->SetStreamSource(0, mQuadVertexBuffer, 0, 0);
+
+ device->SetVertexDeclaration(mQuadVertexDeclaration);
+
+ hr = device->EndStateBlock(&mSavedStateBlock);
+ ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+ }
+
+ ASSERT(mSavedStateBlock != nullptr);
+
+ if (mSavedStateBlock != nullptr)
+ {
+ hr = mSavedStateBlock->Capture();
+ ASSERT(SUCCEEDED(hr));
+ }
+}
+
+void Blit9::restoreState()
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ device->SetDepthStencilSurface(mSavedDepthStencil);
+ SafeRelease(mSavedDepthStencil);
+
+ device->SetRenderTarget(0, mSavedRenderTarget);
+ SafeRelease(mSavedRenderTarget);
+
+ ASSERT(mSavedStateBlock != nullptr);
+
+ if (mSavedStateBlock != nullptr)
+ {
+ mSavedStateBlock->Apply();
+ }
+}
+} // namespace rx