summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/libANGLE/renderer/d3d/d3d9
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/src/libANGLE/renderer/d3d/d3d9')
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp694
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h97
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp112
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h50
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp258
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/Context9.h126
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp36
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h29
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp94
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h38
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp410
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h54
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp822
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h80
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp167
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h49
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp39
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h35
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp189
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h48
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp163
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h98
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp3032
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h487
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h108
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp47
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h35
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp945
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h209
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp442
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h71
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp617
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h134
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h29
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp165
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h50
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp255
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h65
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp659
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h94
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp659
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h95
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps33
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs43
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h84
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/flipyvs.h66
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceps.h94
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/passthroughps.h61
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/standardvs.h66
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/generate_shaders.bat63
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h200
51 files changed, 12596 insertions, 0 deletions
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp
new file mode 100755
index 000000000..95320f228
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp
@@ -0,0 +1,694 @@
+//
+// Copyright (c) 2002-2010 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/renderer/d3d/d3d9/renderer9_utils.h"
+#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
+#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h"
+#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+#include "libANGLE/angletypes.h"
+#include "libANGLE/Framebuffer.h"
+#include "libANGLE/FramebufferAttachment.h"
+
+namespace
+{
+// Precompiled shaders
+#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/standardvs.h"
+#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/flipyvs.h"
+#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/passthroughps.h"
+#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceps.h"
+#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h"
+
+const BYTE* const g_shaderCode[] =
+{
+ g_vs20_standardvs,
+ g_vs20_flipyvs,
+ g_ps20_passthroughps,
+ g_ps20_luminanceps,
+ g_ps20_componentmaskps
+};
+
+const size_t g_shaderSize[] =
+{
+ sizeof(g_vs20_standardvs),
+ sizeof(g_vs20_flipyvs),
+ sizeof(g_ps20_passthroughps),
+ sizeof(g_ps20_luminanceps),
+ sizeof(g_ps20_componentmaskps)
+};
+}
+
+namespace rx
+{
+
+Blit9::Blit9(Renderer9 *renderer)
+ : mRenderer(renderer),
+ mGeometryLoaded(false),
+ mQuadVertexBuffer(NULL),
+ mQuadVertexDeclaration(NULL),
+ mSavedStateBlock(NULL),
+ mSavedRenderTarget(NULL),
+ mSavedDepthStencil(NULL)
+{
+ memset(mCompiledShaders, 0, sizeof(mCompiledShaders));
+}
+
+Blit9::~Blit9()
+{
+ SafeRelease(mSavedStateBlock);
+ SafeRelease(mQuadVertexBuffer);
+ SafeRelease(mQuadVertexDeclaration);
+
+ for (int i = 0; i < SHADER_COUNT; i++)
+ {
+ SafeRelease(mCompiledShaders[i]);
+ }
+}
+
+gl::Error Blit9::initialize()
+{
+ if (mGeometryLoaded)
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ 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, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal blit vertex shader, result: 0x%X.", result);
+ }
+
+ void *lockPtr = NULL;
+ result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0);
+
+ if (FAILED(result) || lockPtr == NULL)
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ SafeRelease(mQuadVertexBuffer);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal blit vertex shader, result: 0x%X.", result);
+ }
+
+ 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);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ SafeRelease(mQuadVertexBuffer);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal blit vertex declaration, result: 0x%X.", result);
+ }
+
+ mGeometryLoaded = true;
+ return gl::Error(GL_NO_ERROR);
+}
+
+template <class D3DShaderType>
+gl::Error Blit9::setShader(ShaderId source, const char *profile,
+ gl::Error (Renderer9::*createShader)(const DWORD *, size_t length, D3DShaderType **outShader),
+ HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*))
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ D3DShaderType *shader = nullptr;
+
+ if (mCompiledShaders[source] != NULL)
+ {
+ shader = static_cast<D3DShaderType*>(mCompiledShaders[source]);
+ }
+ else
+ {
+ const BYTE* shaderCode = g_shaderCode[source];
+ size_t shaderSize = g_shaderSize[source];
+ ANGLE_TRY((mRenderer->*createShader)(reinterpret_cast<const DWORD*>(shaderCode), shaderSize, &shader));
+ mCompiledShaders[source] = shader;
+ }
+
+ HRESULT hr = (device->*setShader)(shader);
+ if (FAILED(hr))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to set shader for blit operation, result: 0x%X.", hr);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Blit9::setVertexShader(ShaderId shader)
+{
+ return setShader<IDirect3DVertexShader9>(shader, "vs_2_0", &Renderer9::createVertexShader, &IDirect3DDevice9::SetVertexShader);
+}
+
+gl::Error Blit9::setPixelShader(ShaderId shader)
+{
+ return setShader<IDirect3DPixelShader9>(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::Error Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest)
+{
+ ANGLE_TRY(initialize());
+
+ IDirect3DTexture9 *texture = NULL;
+ ANGLE_TRY(copySurfaceToTexture(source, getSurfaceRect(source), &texture));
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ saveState();
+
+ device->SetTexture(0, texture);
+ device->SetRenderTarget(0, dest);
+
+ setVertexShader(SHADER_VS_STANDARD);
+ setPixelShader(SHADER_PS_PASSTHROUGH);
+
+ setCommonBlitState();
+ device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+ device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+
+ setViewport(getSurfaceRect(dest), gl::Offset(0, 0, 0));
+
+ render();
+
+ SafeRelease(texture);
+
+ restoreState();
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Blit9::copy2D(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLint level)
+{
+ ANGLE_TRY(initialize());
+
+ const gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0);
+ ASSERT(colorbuffer);
+
+ RenderTarget9 *renderTarget9 = nullptr;
+ ANGLE_TRY(colorbuffer->getRenderTarget(&renderTarget9));
+ ASSERT(renderTarget9);
+
+ IDirect3DSurface9 *source = renderTarget9->getSurface();
+ ASSERT(source);
+
+ IDirect3DSurface9 *destSurface = NULL;
+ TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
+ gl::Error error = storage9->getSurfaceLevel(GL_TEXTURE_2D, level, true, &destSurface);
+ if (error.isError())
+ {
+ SafeRelease(source);
+ return error;
+ }
+ ASSERT(destSurface);
+
+ gl::Error result = copy(source, sourceRect, destFormat, destOffset, destSurface);
+
+ SafeRelease(destSurface);
+ SafeRelease(source);
+
+ return result;
+}
+
+gl::Error Blit9::copyCube(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level)
+{
+ gl::Error error = initialize();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ const gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0);
+ ASSERT(colorbuffer);
+
+ RenderTarget9 *renderTarget9 = nullptr;
+ error = colorbuffer->getRenderTarget(&renderTarget9);
+ if (error.isError())
+ {
+ return error;
+ }
+ ASSERT(renderTarget9);
+
+ IDirect3DSurface9 *source = renderTarget9->getSurface();
+ ASSERT(source);
+
+ IDirect3DSurface9 *destSurface = NULL;
+ TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
+ error = storage9->getSurfaceLevel(target, level, true, &destSurface);
+ if (error.isError())
+ {
+ SafeRelease(source);
+ return error;
+ }
+ ASSERT(destSurface);
+
+ gl::Error result = copy(source, sourceRect, destFormat, destOffset, destSurface);
+
+ SafeRelease(destSurface);
+ SafeRelease(source);
+
+ return result;
+}
+
+gl::Error Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest)
+{
+ ASSERT(source != NULL && dest != NULL);
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ D3DSURFACE_DESC sourceDesc;
+ D3DSURFACE_DESC destDesc;
+ source->GetDesc(&sourceDesc);
+ dest->GetDesc(&destDesc);
+
+ if (sourceDesc.Format == destDesc.Format && destDesc.Usage & D3DUSAGE_RENDERTARGET &&
+ d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat)) // Can use StretchRect
+ {
+ 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);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to blit between textures, StretchRect result: 0x%X.", result);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+ }
+ else
+ {
+ return formatConvert(source, sourceRect, destFormat, destOffset, dest);
+ }
+}
+
+gl::Error Blit9::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest)
+{
+ gl::Error error = initialize();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ IDirect3DTexture9 *texture = NULL;
+ error = copySurfaceToTexture(source, sourceRect, &texture);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ saveState();
+
+ device->SetTexture(0, texture);
+ device->SetRenderTarget(0, dest);
+
+ setViewport(sourceRect, destOffset);
+
+ setCommonBlitState();
+
+ error = setFormatConvertShaders(destFormat);
+ if (!error.isError())
+ {
+ render();
+ }
+
+ SafeRelease(texture);
+
+ restoreState();
+
+ return error;
+}
+
+gl::Error Blit9::setFormatConvertShaders(GLenum destFormat)
+{
+ gl::Error error = setVertexShader(SHADER_VS_STANDARD);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ switch (destFormat)
+ {
+ default: UNREACHABLE();
+ case GL_RGBA:
+ case GL_BGRA_EXT:
+ case GL_RGB:
+ case GL_RG_EXT:
+ case GL_RED_EXT:
+ case GL_ALPHA:
+ error = setPixelShader(SHADER_PS_COMPONENTMASK);
+ break;
+
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ error = setPixelShader(SHADER_PS_LUMINANCE);
+ break;
+ }
+
+ if (error.isError())
+ {
+ return error;
+ }
+
+ 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)
+ {
+ default: UNREACHABLE();
+ 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;
+ }
+
+ mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst, 2);
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect, IDirect3DTexture9 **outTexture)
+{
+ ASSERT(surface);
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ D3DSURFACE_DESC sourceDesc;
+ surface->GetDesc(&sourceDesc);
+
+ const auto destWidth = sourceRect.right - sourceRect.left;
+ const auto destHeight = sourceRect.bottom - sourceRect.top;
+
+ // Copy the render target into a texture
+ IDirect3DTexture9 *texture;
+ HRESULT result = device->CreateTexture(destWidth, destHeight, 1, D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal texture for blit, result: 0x%X.", result);
+ }
+
+ IDirect3DSurface9 *textureSurface;
+ result = texture->GetSurfaceLevel(0, &textureSurface);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ SafeRelease(texture);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to query surface of internal blit texture, result: 0x%X.", result);
+ }
+
+ mRenderer->endScene();
+
+ if (sourceRect.left < sourceDesc.Width && sourceRect.right > 0 &&
+ sourceRect.top < sourceDesc.Height && sourceRect.bottom > 0)
+ {
+ RECT validSourceRect = sourceRect;
+ RECT validDestRect = {0, 0, destWidth, destHeight};
+
+ if (sourceRect.left < 0) {
+ validSourceRect.left += 0 - sourceRect.left;
+ validDestRect.left += 0 - sourceRect.left;
+ }
+
+ if (sourceRect.right > sourceDesc.Width) {
+ validSourceRect.right -= sourceRect.right - sourceDesc.Width;
+ validDestRect.right -= sourceRect.right - sourceDesc.Width;
+ }
+
+ if (sourceRect.top < 0) {
+ validSourceRect.top += 0 - sourceRect.top;
+ validDestRect.top += 0 - sourceRect.top;
+ }
+
+ if (sourceRect.bottom > sourceDesc.Height) {
+ validSourceRect.bottom -= sourceRect.bottom - sourceDesc.Height;
+ validDestRect.bottom -= sourceRect.bottom - sourceDesc.Height;
+ }
+
+ ASSERT(validSourceRect.left < validSourceRect.right);
+ ASSERT(validSourceRect.top < validSourceRect.bottom);
+ ASSERT(validDestRect.left < validDestRect.right);
+ ASSERT(validDestRect.top < validDestRect.bottom);
+ result = device->StretchRect(surface, &validSourceRect, textureSurface,
+ &validDestRect, D3DTEXF_NONE);
+ }
+ SafeRelease(textureSurface);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ SafeRelease(texture);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to copy between internal blit textures, result: 0x%X.", result);
+ }
+
+ *outTexture = texture;
+ return gl::Error(GL_NO_ERROR);
+}
+
+void Blit9::setViewport(const RECT &sourceRect, const gl::Offset &offset)
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ D3DVIEWPORT9 vp;
+ vp.X = offset.x;
+ vp.Y = offset.y;
+ vp.Width = sourceRect.right - sourceRect.left;
+ vp.Height = sourceRect.bottom - sourceRect.top;
+ vp.MinZ = 0.0f;
+ vp.MaxZ = 1.0f;
+ device->SetViewport(&vp);
+
+ float halfPixelAdjust[4] = { -1.0f/vp.Width, 1.0f/vp.Height, 0, 0 };
+ device->SetVertexShaderConstantF(0, halfPixelAdjust, 1);
+}
+
+void Blit9::setCommonBlitState()
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ device->SetDepthStencilSurface(NULL);
+
+ 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 = {0}; // 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();
+
+ HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float));
+ hr = device->SetVertexDeclaration(mQuadVertexDeclaration);
+
+ mRenderer->startScene();
+ hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
+}
+
+void Blit9::saveState()
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ HRESULT hr;
+
+ device->GetDepthStencilSurface(&mSavedDepthStencil);
+ device->GetRenderTarget(0, &mSavedRenderTarget);
+
+ if (mSavedStateBlock == NULL)
+ {
+ hr = device->BeginStateBlock();
+ ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+
+ setCommonBlitState();
+
+ static const float dummyConst[8] = { 0 };
+
+ device->SetVertexShader(NULL);
+ device->SetVertexShaderConstantF(0, dummyConst, 2);
+ device->SetPixelShader(NULL);
+ device->SetPixelShaderConstantF(0, dummyConst, 2);
+
+ D3DVIEWPORT9 dummyVp;
+ dummyVp.X = 0;
+ dummyVp.Y = 0;
+ dummyVp.Width = 1;
+ dummyVp.Height = 1;
+ dummyVp.MinZ = 0;
+ dummyVp.MaxZ = 1;
+
+ device->SetViewport(&dummyVp);
+
+ device->SetTexture(0, NULL);
+
+ device->SetStreamSource(0, mQuadVertexBuffer, 0, 0);
+
+ device->SetVertexDeclaration(mQuadVertexDeclaration);
+
+ hr = device->EndStateBlock(&mSavedStateBlock);
+ ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+ }
+
+ ASSERT(mSavedStateBlock != NULL);
+
+ if (mSavedStateBlock != NULL)
+ {
+ 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 != NULL);
+
+ if (mSavedStateBlock != NULL)
+ {
+ mSavedStateBlock->Apply();
+ }
+}
+
+}
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h
new file mode 100755
index 000000000..586abd258
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h
@@ -0,0 +1,97 @@
+//
+// Copyright (c) 2002-2010 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.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_BLIT9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_BLIT9_H_
+
+#include "common/angleutils.h"
+#include "libANGLE/Error.h"
+
+#include <GLES2/gl2.h>
+
+namespace gl
+{
+class Framebuffer;
+struct Offset;
+}
+
+namespace rx
+{
+class Renderer9;
+class TextureStorage;
+
+class Blit9 : angle::NonCopyable
+{
+ public:
+ explicit Blit9(Renderer9 *renderer);
+ ~Blit9();
+
+ gl::Error initialize();
+
+ // Copy from source surface to dest surface.
+ // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left)
+ gl::Error copy2D(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLint level);
+ gl::Error copyCube(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level);
+
+ // Copy from source surface to dest surface.
+ // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left)
+ // source is interpreted as RGBA and destFormat specifies the desired result format. For example, if destFormat = GL_RGB, the alpha channel will be forced to 0.
+ gl::Error formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest);
+
+ // 2x2 box filter sample from source to dest.
+ // Requires that source is RGB(A) and dest has the same format as source.
+ gl::Error boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest);
+
+ private:
+ Renderer9 *mRenderer;
+
+ bool mGeometryLoaded;
+ IDirect3DVertexBuffer9 *mQuadVertexBuffer;
+ IDirect3DVertexDeclaration9 *mQuadVertexDeclaration;
+
+ gl::Error setFormatConvertShaders(GLenum destFormat);
+
+ gl::Error copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest);
+ gl::Error copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect, IDirect3DTexture9 **outTexture);
+ void setViewport(const RECT &sourceRect, const gl::Offset &offset);
+ void setCommonBlitState();
+ RECT getSurfaceRect(IDirect3DSurface9 *surface) const;
+
+ // This enum is used to index mCompiledShaders and mShaderSource.
+ enum ShaderId
+ {
+ SHADER_VS_STANDARD,
+ SHADER_VS_FLIPY,
+ SHADER_PS_PASSTHROUGH,
+ SHADER_PS_LUMINANCE,
+ SHADER_PS_COMPONENTMASK,
+ SHADER_COUNT
+ };
+
+ // This actually contains IDirect3DVertexShader9 or IDirect3DPixelShader9 casted to IUnknown.
+ IUnknown *mCompiledShaders[SHADER_COUNT];
+
+ template <class D3DShaderType>
+ gl::Error setShader(ShaderId source, const char *profile,
+ gl::Error (Renderer9::*createShader)(const DWORD *, size_t length, D3DShaderType **outShader),
+ HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*));
+
+ gl::Error setVertexShader(ShaderId shader);
+ gl::Error setPixelShader(ShaderId shader);
+ void render();
+
+ void saveState();
+ void restoreState();
+ IDirect3DStateBlock9 *mSavedStateBlock;
+ IDirect3DSurface9 *mSavedRenderTarget;
+ IDirect3DSurface9 *mSavedDepthStencil;
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_BLIT9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp
new file mode 100755
index 000000000..b8abf3845
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp
@@ -0,0 +1,112 @@
+//
+// Copyright 2014 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.
+//
+
+// Buffer9.cpp Defines the Buffer9 class.
+
+#include "libANGLE/renderer/d3d/d3d9/Buffer9.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+
+namespace rx
+{
+
+Buffer9::Buffer9(const gl::BufferState &state, Renderer9 *renderer)
+ : BufferD3D(state, renderer), mSize(0)
+{}
+
+Buffer9::~Buffer9()
+{
+ mSize = 0;
+}
+
+gl::Error Buffer9::setData(GLenum /*target*/, const void *data, size_t size, GLenum usage)
+{
+ if (size > mMemory.size())
+ {
+ if (!mMemory.resize(size))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer.");
+ }
+ }
+
+ mSize = size;
+ if (data && size > 0)
+ {
+ memcpy(mMemory.data(), data, size);
+ }
+
+ updateD3DBufferUsage(usage);
+
+ invalidateStaticData();
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Buffer9::getData(const uint8_t **outData)
+{
+ *outData = mMemory.data();
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Buffer9::setSubData(GLenum /*target*/, const void *data, size_t size, size_t offset)
+{
+ if (offset + size > mMemory.size())
+ {
+ if (!mMemory.resize(offset + size))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer.");
+ }
+ }
+
+ mSize = std::max(mSize, offset + size);
+ if (data && size > 0)
+ {
+ memcpy(mMemory.data() + offset, data, size);
+ }
+
+ invalidateStaticData();
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Buffer9::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size)
+{
+ // Note: this method is currently unreachable
+ Buffer9* sourceBuffer = GetAs<Buffer9>(source);
+ ASSERT(sourceBuffer);
+
+ memcpy(mMemory.data() + destOffset, sourceBuffer->mMemory.data() + sourceOffset, size);
+
+ invalidateStaticData();
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+// We do not support buffer mapping in D3D9
+gl::Error Buffer9::map(GLenum access, GLvoid **mapPtr)
+{
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+gl::Error Buffer9::mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr)
+{
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+gl::Error Buffer9::unmap(GLboolean *result)
+{
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+gl::Error Buffer9::markTransformFeedbackUsage()
+{
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+} // namespace rx
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h
new file mode 100755
index 000000000..dd7671827
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h
@@ -0,0 +1,50 @@
+//
+// Copyright 2014 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.
+//
+
+// Buffer9.h: Defines the rx::Buffer9 class which implements rx::BufferImpl via rx::BufferD3D.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_BUFFER9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_BUFFER9_H_
+
+#include "common/MemoryBuffer.h"
+#include "libANGLE/angletypes.h"
+#include "libANGLE/renderer/d3d/BufferD3D.h"
+
+namespace rx
+{
+class Renderer9;
+
+class Buffer9 : public BufferD3D
+{
+ public:
+ Buffer9(const gl::BufferState &state, Renderer9 *renderer);
+ virtual ~Buffer9();
+
+ // BufferD3D implementation
+ virtual size_t getSize() const { return mSize; }
+ virtual bool supportsDirectBinding() const { return false; }
+ gl::Error getData(const uint8_t **outData) override;
+
+ // BufferImpl implementation
+ gl::Error setData(GLenum target, const void *data, size_t size, GLenum usage) override;
+ gl::Error setSubData(GLenum target, const void *data, size_t size, size_t offset) override;
+ gl::Error copySubData(BufferImpl *source,
+ GLintptr sourceOffset,
+ GLintptr destOffset,
+ GLsizeiptr size) override;
+ gl::Error map(GLenum access, GLvoid **mapPtr) override;
+ gl::Error mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) override;
+ gl::Error unmap(GLboolean *result) override;
+ gl::Error markTransformFeedbackUsage() override;
+
+ private:
+ MemoryBuffer mMemory;
+ size_t mSize;
+};
+
+} // namespace rx
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_BUFFER9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp
new file mode 100755
index 000000000..c38bc1b11
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp
@@ -0,0 +1,258 @@
+//
+// Copyright 2016 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.
+//
+// Context9:
+// D3D9-specific functionality associated with a GL Context.
+//
+
+#include "libANGLE/renderer/d3d/d3d9/Context9.h"
+
+#include "common/string_utils.h"
+#include "libANGLE/renderer/d3d/CompilerD3D.h"
+#include "libANGLE/renderer/d3d/ShaderD3D.h"
+#include "libANGLE/renderer/d3d/ProgramD3D.h"
+#include "libANGLE/renderer/d3d/RenderbufferD3D.h"
+#include "libANGLE/renderer/d3d/SamplerD3D.h"
+#include "libANGLE/renderer/d3d/TextureD3D.h"
+#include "libANGLE/renderer/d3d/d3d9/Buffer9.h"
+#include "libANGLE/renderer/d3d/d3d9/Fence9.h"
+#include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h"
+#include "libANGLE/renderer/d3d/d3d9/Query9.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+#include "libANGLE/renderer/d3d/d3d9/StateManager9.h"
+#include "libANGLE/renderer/d3d/d3d9/VertexArray9.h"
+
+namespace rx
+{
+
+Context9::Context9(const gl::ContextState &state, Renderer9 *renderer)
+ : ContextImpl(state), mRenderer(renderer)
+{
+}
+
+Context9::~Context9()
+{
+}
+
+gl::Error Context9::initialize()
+{
+ return gl::NoError();
+}
+
+CompilerImpl *Context9::createCompiler()
+{
+ return new CompilerD3D(SH_HLSL_3_0_OUTPUT);
+}
+
+ShaderImpl *Context9::createShader(const gl::ShaderState &data)
+{
+ return new ShaderD3D(data, mRenderer->getWorkarounds());
+}
+
+ProgramImpl *Context9::createProgram(const gl::ProgramState &data)
+{
+ return new ProgramD3D(data, mRenderer);
+}
+
+FramebufferImpl *Context9::createFramebuffer(const gl::FramebufferState &data)
+{
+ return new Framebuffer9(data, mRenderer);
+}
+
+TextureImpl *Context9::createTexture(const gl::TextureState &state)
+{
+ switch (state.getTarget())
+ {
+ case GL_TEXTURE_2D:
+ return new TextureD3D_2D(state, mRenderer);
+ case GL_TEXTURE_CUBE_MAP:
+ return new TextureD3D_Cube(state, mRenderer);
+ case GL_TEXTURE_EXTERNAL_OES:
+ return new TextureD3D_External(state, mRenderer);
+ default:
+ UNREACHABLE();
+ }
+ return nullptr;
+}
+
+RenderbufferImpl *Context9::createRenderbuffer()
+{
+ return new RenderbufferD3D(mRenderer);
+}
+
+BufferImpl *Context9::createBuffer(const gl::BufferState &state)
+{
+ return new Buffer9(state, mRenderer);
+}
+
+VertexArrayImpl *Context9::createVertexArray(const gl::VertexArrayState &data)
+{
+ return new VertexArray9(data);
+}
+
+QueryImpl *Context9::createQuery(GLenum type)
+{
+ return new Query9(mRenderer, type);
+}
+
+FenceNVImpl *Context9::createFenceNV()
+{
+ return new FenceNV9(mRenderer);
+}
+
+FenceSyncImpl *Context9::createFenceSync()
+{
+ // D3D9 doesn't support ES 3.0 and its sync objects.
+ UNREACHABLE();
+ return nullptr;
+}
+
+TransformFeedbackImpl *Context9::createTransformFeedback(const gl::TransformFeedbackState &state)
+{
+ UNREACHABLE();
+ return nullptr;
+}
+
+SamplerImpl *Context9::createSampler()
+{
+ return new SamplerD3D();
+}
+
+std::vector<PathImpl *> Context9::createPaths(GLsizei)
+{
+ return std::vector<PathImpl *>();
+}
+
+gl::Error Context9::flush()
+{
+ return mRenderer->flush();
+}
+
+gl::Error Context9::finish()
+{
+ return mRenderer->finish();
+}
+
+gl::Error Context9::drawArrays(GLenum mode, GLint first, GLsizei count)
+{
+ return mRenderer->genericDrawArrays(this, mode, first, count, 1);
+}
+
+gl::Error Context9::drawArraysInstanced(GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei instanceCount)
+{
+ return mRenderer->genericDrawArrays(this, mode, first, count, instanceCount);
+}
+
+gl::Error Context9::drawElements(GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const gl::IndexRange &indexRange)
+{
+ return mRenderer->genericDrawElements(this, mode, count, type, indices, 1, indexRange);
+}
+
+gl::Error Context9::drawElementsInstanced(GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances,
+ const gl::IndexRange &indexRange)
+{
+ return mRenderer->genericDrawElements(this, mode, count, type, indices, instances, indexRange);
+}
+
+gl::Error Context9::drawRangeElements(GLenum mode,
+ GLuint start,
+ GLuint end,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const gl::IndexRange &indexRange)
+{
+ return mRenderer->genericDrawElements(this, mode, count, type, indices, 1, indexRange);
+}
+
+GLenum Context9::getResetStatus()
+{
+ return mRenderer->getResetStatus();
+}
+
+std::string Context9::getVendorString() const
+{
+ return mRenderer->getVendorString();
+}
+
+std::string Context9::getRendererDescription() const
+{
+ return mRenderer->getRendererDescription();
+}
+
+void Context9::insertEventMarker(GLsizei length, const char *marker)
+{
+ auto optionalString = angle::WidenString(static_cast<size_t>(length), marker);
+ if (optionalString.valid())
+ {
+ mRenderer->getAnnotator()->setMarker(optionalString.value().data());
+ }
+}
+
+void Context9::pushGroupMarker(GLsizei length, const char *marker)
+{
+ auto optionalString = angle::WidenString(static_cast<size_t>(length), marker);
+ if (optionalString.valid())
+ {
+ mRenderer->getAnnotator()->beginEvent(optionalString.value().data());
+ }
+}
+
+void Context9::popGroupMarker()
+{
+ mRenderer->getAnnotator()->endEvent();
+}
+
+void Context9::syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits)
+{
+ mRenderer->getStateManager()->syncState(state, dirtyBits);
+}
+
+GLint Context9::getGPUDisjoint()
+{
+ return mRenderer->getGPUDisjoint();
+}
+
+GLint64 Context9::getTimestamp()
+{
+ return mRenderer->getTimestamp();
+}
+
+void Context9::onMakeCurrent(const gl::ContextState &data)
+{
+}
+
+const gl::Caps &Context9::getNativeCaps() const
+{
+ return mRenderer->getNativeCaps();
+}
+
+const gl::TextureCapsMap &Context9::getNativeTextureCaps() const
+{
+ return mRenderer->getNativeTextureCaps();
+}
+
+const gl::Extensions &Context9::getNativeExtensions() const
+{
+ return mRenderer->getNativeExtensions();
+}
+
+const gl::Limitations &Context9::getNativeLimitations() const
+{
+ return mRenderer->getNativeLimitations();
+}
+
+} // namespace rx
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Context9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Context9.h
new file mode 100755
index 000000000..aeb18ff5e
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Context9.h
@@ -0,0 +1,126 @@
+//
+// Copyright 2016 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.
+//
+// Context9:
+// D3D9-specific functionality associated with a GL Context.
+//
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_CONTEXT9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_CONTEXT9_H_
+
+#include "libANGLE/renderer/ContextImpl.h"
+
+namespace rx
+{
+class Renderer9;
+
+class Context9 : public ContextImpl
+{
+ public:
+ Context9(const gl::ContextState &state, Renderer9 *renderer);
+ ~Context9() override;
+
+ gl::Error initialize() override;
+
+ // Shader creation
+ CompilerImpl *createCompiler() override;
+ ShaderImpl *createShader(const gl::ShaderState &data) override;
+ ProgramImpl *createProgram(const gl::ProgramState &data) override;
+
+ // Framebuffer creation
+ FramebufferImpl *createFramebuffer(const gl::FramebufferState &data) override;
+
+ // Texture creation
+ TextureImpl *createTexture(const gl::TextureState &state) override;
+
+ // Renderbuffer creation
+ RenderbufferImpl *createRenderbuffer() override;
+
+ // Buffer creation
+ BufferImpl *createBuffer(const gl::BufferState &state) override;
+
+ // Vertex Array creation
+ VertexArrayImpl *createVertexArray(const gl::VertexArrayState &data) override;
+
+ // Query and Fence creation
+ QueryImpl *createQuery(GLenum type) override;
+ FenceNVImpl *createFenceNV() override;
+ FenceSyncImpl *createFenceSync() override;
+
+ // Transform Feedback creation
+ TransformFeedbackImpl *createTransformFeedback(
+ const gl::TransformFeedbackState &state) override;
+
+ // Sampler object creation
+ SamplerImpl *createSampler() override;
+
+ // Path object creation
+ std::vector<PathImpl *> createPaths(GLsizei) override;
+
+ // Flush and finish.
+ gl::Error flush() override;
+ gl::Error finish() override;
+
+ // Drawing methods.
+ gl::Error drawArrays(GLenum mode, GLint first, GLsizei count) override;
+ gl::Error drawArraysInstanced(GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei instanceCount) override;
+
+ gl::Error drawElements(GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const gl::IndexRange &indexRange) override;
+ gl::Error drawElementsInstanced(GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances,
+ const gl::IndexRange &indexRange) override;
+ gl::Error drawRangeElements(GLenum mode,
+ GLuint start,
+ GLuint end,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const gl::IndexRange &indexRange) override;
+
+ // Device loss
+ GLenum getResetStatus() override;
+
+ // Vendor and description strings.
+ std::string getVendorString() const override;
+ std::string getRendererDescription() const override;
+
+ // Debug markers.
+ void insertEventMarker(GLsizei length, const char *marker) override;
+ void pushGroupMarker(GLsizei length, const char *marker) override;
+ void popGroupMarker() override;
+
+ // State sync with dirty bits.
+ void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits) override;
+
+ // Disjoint timer queries
+ GLint getGPUDisjoint() override;
+ GLint64 getTimestamp() override;
+
+ // Context switching
+ void onMakeCurrent(const gl::ContextState &data) override;
+
+ // Caps queries
+ const gl::Caps &getNativeCaps() const override;
+ const gl::TextureCapsMap &getNativeTextureCaps() const override;
+ const gl::Extensions &getNativeExtensions() const override;
+ const gl::Limitations &getNativeLimitations() const override;
+
+ private:
+ Renderer9 *mRenderer;
+};
+
+} // namespace rx
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_CONTEXT9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp
new file mode 100755
index 000000000..6ec35e16a
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp
@@ -0,0 +1,36 @@
+//
+// Copyright 2015 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.
+//
+// DebugAnnotator9.h: D3D9 helpers for adding trace annotations.
+//
+
+#include "libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h"
+
+#include "common/platform.h"
+
+namespace rx
+{
+
+void DebugAnnotator9::beginEvent(const wchar_t *eventName)
+{
+ D3DPERF_BeginEvent(0, eventName);
+}
+
+void DebugAnnotator9::endEvent()
+{
+ D3DPERF_EndEvent();
+}
+
+void DebugAnnotator9::setMarker(const wchar_t *markerName)
+{
+ D3DPERF_SetMarker(0, markerName);
+}
+
+bool DebugAnnotator9::getStatus()
+{
+ return !!D3DPERF_GetStatus();
+}
+
+}
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h
new file mode 100755
index 000000000..54e3bb949
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h
@@ -0,0 +1,29 @@
+//
+// Copyright 2015 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.
+//
+// DebugAnnotator9.h: D3D9 helpers for adding trace annotations.
+//
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_DEBUGANNOTATOR9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_DEBUGANNOTATOR9_H_
+
+#include "common/debug.h"
+
+namespace rx
+{
+
+class DebugAnnotator9 : public gl::DebugAnnotator
+{
+ public:
+ DebugAnnotator9() {}
+ void beginEvent(const wchar_t *eventName) override;
+ void endEvent() override;
+ void setMarker(const wchar_t *markerName) override;
+ bool getStatus() override;
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_DEBUGANNOTATOR9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp
new file mode 100755
index 000000000..330068127
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp
@@ -0,0 +1,94 @@
+//
+// Copyright (c) 2013 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.
+//
+
+// Fence9.cpp: Defines the rx::FenceNV9 class.
+
+#include "libANGLE/renderer/d3d/d3d9/Fence9.h"
+#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+
+namespace rx
+{
+
+FenceNV9::FenceNV9(Renderer9 *renderer)
+ : FenceNVImpl(),
+ mRenderer(renderer),
+ mQuery(NULL)
+{
+}
+
+FenceNV9::~FenceNV9()
+{
+ SafeRelease(mQuery);
+}
+
+gl::Error FenceNV9::set(GLenum condition)
+{
+ if (!mQuery)
+ {
+ gl::Error error = mRenderer->allocateEventQuery(&mQuery);
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+
+ HRESULT result = mQuery->Issue(D3DISSUE_END);
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ SafeRelease(mQuery);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to end event query, result: 0x%X.", result);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error FenceNV9::test(GLboolean *outFinished)
+{
+ return testHelper(true, outFinished);
+}
+
+gl::Error FenceNV9::finish()
+{
+ GLboolean finished = GL_FALSE;
+ while (finished != GL_TRUE)
+ {
+ gl::Error error = testHelper(true, &finished);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ Sleep(0);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error FenceNV9::testHelper(bool flushCommandBuffer, GLboolean *outFinished)
+{
+ ASSERT(mQuery);
+
+ DWORD getDataFlags = (flushCommandBuffer ? D3DGETDATA_FLUSH : 0);
+ HRESULT result = mQuery->GetData(NULL, 0, getDataFlags);
+
+ if (d3d9::isDeviceLostError(result))
+ {
+ mRenderer->notifyDeviceLost();
+ return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while querying result of an event query.");
+ }
+ else if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to get query data, result: 0x%X.", result);
+ }
+
+ ASSERT(result == S_OK || result == S_FALSE);
+ *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE);
+ return gl::Error(GL_NO_ERROR);
+}
+
+}
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h
new file mode 100755
index 000000000..200ac68d2
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h
@@ -0,0 +1,38 @@
+//
+// Copyright (c) 2013 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.
+//
+
+// Fence9.h: Defines the rx::FenceNV9 class which implements rx::FenceNVImpl.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_FENCE9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_FENCE9_H_
+
+#include "libANGLE/renderer/FenceNVImpl.h"
+#include "libANGLE/renderer/FenceSyncImpl.h"
+
+namespace rx
+{
+class Renderer9;
+
+class FenceNV9 : public FenceNVImpl
+{
+ public:
+ explicit FenceNV9(Renderer9 *renderer);
+ ~FenceNV9() override;
+
+ gl::Error set(GLenum condition) override;
+ gl::Error test(GLboolean *outFinished) override;
+ gl::Error finish() override;
+
+ private:
+ gl::Error testHelper(bool flushCommandBuffer, GLboolean *outFinished);
+
+ Renderer9 *mRenderer;
+ IDirect3DQuery9 *mQuery;
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_FENCE9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp
new file mode 100755
index 000000000..18e1b3da4
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp
@@ -0,0 +1,410 @@
+//
+// Copyright 2014 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.
+//
+
+// Framebuffer9.cpp: Implements the Framebuffer9 class.
+
+#include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h"
+
+#include "libANGLE/Framebuffer.h"
+#include "libANGLE/FramebufferAttachment.h"
+#include "libANGLE/Texture.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/ContextImpl.h"
+#include "libANGLE/renderer/renderer_utils.h"
+#include "libANGLE/renderer/d3d/TextureD3D.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
+#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h"
+#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
+#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
+
+namespace rx
+{
+
+Framebuffer9::Framebuffer9(const gl::FramebufferState &data, Renderer9 *renderer)
+ : FramebufferD3D(data, renderer), mRenderer(renderer)
+{
+ ASSERT(mRenderer != nullptr);
+}
+
+Framebuffer9::~Framebuffer9()
+{
+}
+
+gl::Error Framebuffer9::discard(size_t, const GLenum *)
+{
+ // Extension not implemented in D3D9 renderer
+ UNREACHABLE();
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Framebuffer9::invalidate(size_t, const GLenum *)
+{
+ // Shouldn't ever reach here in D3D9
+ UNREACHABLE();
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Framebuffer9::invalidateSub(size_t, const GLenum *, const gl::Rectangle &)
+{
+ // Shouldn't ever reach here in D3D9
+ UNREACHABLE();
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Framebuffer9::clearImpl(ContextImpl *context, const ClearParameters &clearParams)
+{
+ const gl::FramebufferAttachment *colorAttachment = mState.getColorAttachment(0);
+ const gl::FramebufferAttachment *depthStencilAttachment = mState.getDepthOrStencilAttachment();
+
+ gl::Error error =
+ mRenderer->applyRenderTarget(context, colorAttachment, depthStencilAttachment);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ const gl::State &glState = context->getGLState();
+ float nearZ = glState.getNearPlane();
+ float farZ = glState.getFarPlane();
+ mRenderer->setViewport(glState.getViewport(), nearZ, farZ, GL_TRIANGLES,
+ glState.getRasterizerState().frontFace, true);
+
+ mRenderer->setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled());
+
+ return mRenderer->clear(clearParams, colorAttachment, depthStencilAttachment);
+}
+
+gl::Error Framebuffer9::readPixelsImpl(const gl::Rectangle &area,
+ GLenum format,
+ GLenum type,
+ size_t outputPitch,
+ const gl::PixelPackState &pack,
+ uint8_t *pixels) const
+{
+ ASSERT(pack.pixelBuffer.get() == nullptr);
+
+ const gl::FramebufferAttachment *colorbuffer = mState.getColorAttachment(0);
+ ASSERT(colorbuffer);
+
+ RenderTarget9 *renderTarget = nullptr;
+ gl::Error error = colorbuffer->getRenderTarget(&renderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+ ASSERT(renderTarget);
+
+ IDirect3DSurface9 *surface = renderTarget->getSurface();
+ ASSERT(surface);
+
+ D3DSURFACE_DESC desc;
+ surface->GetDesc(&desc);
+
+ if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
+ {
+ UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target
+ SafeRelease(surface);
+ return gl::Error(GL_OUT_OF_MEMORY, "ReadPixels is unimplemented for multisampled framebuffer attachments.");
+ }
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+ ASSERT(device);
+
+ HRESULT result;
+ IDirect3DSurface9 *systemSurface = nullptr;
+ bool directToPixels = !pack.reverseRowOrder && pack.alignment <= 4 && mRenderer->getShareHandleSupport() &&
+ area.x == 0 && area.y == 0 &&
+ static_cast<UINT>(area.width) == desc.Width && static_cast<UINT>(area.height) == desc.Height &&
+ desc.Format == D3DFMT_A8R8G8B8 && format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE;
+ if (directToPixels)
+ {
+ // Use the pixels ptr as a shared handle to write directly into client's memory
+ result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
+ D3DPOOL_SYSTEMMEM, &systemSurface, reinterpret_cast<void**>(&pixels));
+ if (FAILED(result))
+ {
+ // Try again without the shared handle
+ directToPixels = false;
+ }
+ }
+
+ if (!directToPixels)
+ {
+ result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
+ D3DPOOL_SYSTEMMEM, &systemSurface, nullptr);
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ SafeRelease(surface);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal texture for ReadPixels.");
+ }
+ }
+
+ result = device->GetRenderTargetData(surface, systemSurface);
+ SafeRelease(surface);
+
+ if (FAILED(result))
+ {
+ SafeRelease(systemSurface);
+
+ // It turns out that D3D will sometimes produce more error
+ // codes than those documented.
+ if (d3d9::isDeviceLostError(result))
+ {
+ mRenderer->notifyDeviceLost();
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to read internal render target data.");
+ }
+
+ if (directToPixels)
+ {
+ SafeRelease(systemSurface);
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ RECT rect;
+ rect.left = gl::clamp(area.x, 0L, static_cast<LONG>(desc.Width));
+ rect.top = gl::clamp(area.y, 0L, static_cast<LONG>(desc.Height));
+ rect.right = gl::clamp(area.x + area.width, 0L, static_cast<LONG>(desc.Width));
+ rect.bottom = gl::clamp(area.y + area.height, 0L, static_cast<LONG>(desc.Height));
+
+ D3DLOCKED_RECT lock;
+ result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY);
+
+ if (FAILED(result))
+ {
+ UNREACHABLE();
+ SafeRelease(systemSurface);
+
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal render target.");
+ }
+
+ uint8_t *source = reinterpret_cast<uint8_t *>(lock.pBits);
+ int inputPitch = lock.Pitch;
+
+ const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
+ gl::FormatType formatType(format, type);
+
+ // TODO(jmadill): Maybe we can avoid a copy of pack parameters here?
+ PackPixelsParams packParams;
+ packParams.area.x = rect.left;
+ packParams.area.y = rect.top;
+ packParams.area.width = rect.right - rect.left;
+ packParams.area.height = rect.bottom - rect.top;
+ packParams.format = format;
+ packParams.type = type;
+ packParams.outputPitch = static_cast<GLuint>(outputPitch);
+ packParams.pack = pack;
+
+ PackPixels(packParams, d3dFormatInfo.info(), inputPitch, source, pixels);
+
+ systemSurface->UnlockRect();
+ SafeRelease(systemSurface);
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Framebuffer9::blitImpl(const gl::Rectangle &sourceArea,
+ const gl::Rectangle &destArea,
+ const gl::Rectangle *scissor,
+ bool blitRenderTarget,
+ bool blitDepth,
+ bool blitStencil,
+ GLenum filter,
+ const gl::Framebuffer *sourceFramebuffer)
+{
+ ASSERT(filter == GL_NEAREST);
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+ ASSERT(device);
+
+ mRenderer->endScene();
+
+ if (blitRenderTarget)
+ {
+ const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getColorbuffer(0);
+ ASSERT(readBuffer);
+
+ RenderTarget9 *readRenderTarget = nullptr;
+ gl::Error error = readBuffer->getRenderTarget(&readRenderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+ ASSERT(readRenderTarget);
+
+ const gl::FramebufferAttachment *drawBuffer = mState.getColorAttachment(0);
+ ASSERT(drawBuffer);
+
+ RenderTarget9 *drawRenderTarget = nullptr;
+ error = drawBuffer->getRenderTarget(&drawRenderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+ ASSERT(drawRenderTarget);
+
+ // The getSurface calls do an AddRef so save them until after no errors are possible
+ IDirect3DSurface9* readSurface = readRenderTarget->getSurface();
+ ASSERT(readSurface);
+
+ IDirect3DSurface9* drawSurface = drawRenderTarget->getSurface();
+ ASSERT(drawSurface);
+
+ gl::Extents srcSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1);
+ gl::Extents dstSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1);
+
+ RECT srcRect;
+ srcRect.left = sourceArea.x;
+ srcRect.right = sourceArea.x + sourceArea.width;
+ srcRect.top = sourceArea.y;
+ srcRect.bottom = sourceArea.y + sourceArea.height;
+
+ RECT dstRect;
+ dstRect.left = destArea.x;
+ dstRect.right = destArea.x + destArea.width;
+ dstRect.top = destArea.y;
+ dstRect.bottom = destArea.y + destArea.height;
+
+ // Clip the rectangles to the scissor rectangle
+ if (scissor)
+ {
+ if (dstRect.left < scissor->x)
+ {
+ srcRect.left += (scissor->x - dstRect.left);
+ dstRect.left = scissor->x;
+ }
+ if (dstRect.top < scissor->y)
+ {
+ srcRect.top += (scissor->y - dstRect.top);
+ dstRect.top = scissor->y;
+ }
+ if (dstRect.right > scissor->x + scissor->width)
+ {
+ srcRect.right -= (dstRect.right - (scissor->x + scissor->width));
+ dstRect.right = scissor->x + scissor->width;
+ }
+ if (dstRect.bottom > scissor->y + scissor->height)
+ {
+ srcRect.bottom -= (dstRect.bottom - (scissor->y + scissor->height));
+ dstRect.bottom = scissor->y + scissor->height;
+ }
+ }
+
+ // Clip the rectangles to the destination size
+ if (dstRect.left < 0)
+ {
+ srcRect.left += -dstRect.left;
+ dstRect.left = 0;
+ }
+ if (dstRect.right > dstSize.width)
+ {
+ srcRect.right -= (dstRect.right - dstSize.width);
+ dstRect.right = dstSize.width;
+ }
+ if (dstRect.top < 0)
+ {
+ srcRect.top += -dstRect.top;
+ dstRect.top = 0;
+ }
+ if (dstRect.bottom > dstSize.height)
+ {
+ srcRect.bottom -= (dstRect.bottom - dstSize.height);
+ dstRect.bottom = dstSize.height;
+ }
+
+ // Clip the rectangles to the source size
+ if (srcRect.left < 0)
+ {
+ dstRect.left += -srcRect.left;
+ srcRect.left = 0;
+ }
+ if (srcRect.right > srcSize.width)
+ {
+ dstRect.right -= (srcRect.right - srcSize.width);
+ srcRect.right = srcSize.width;
+ }
+ if (srcRect.top < 0)
+ {
+ dstRect.top += -srcRect.top;
+ srcRect.top = 0;
+ }
+ if (srcRect.bottom > srcSize.height)
+ {
+ dstRect.bottom -= (srcRect.bottom - srcSize.height);
+ srcRect.bottom = srcSize.height;
+ }
+
+ HRESULT result = device->StretchRect(readSurface, &srcRect, drawSurface, &dstRect, D3DTEXF_NONE);
+
+ SafeRelease(readSurface);
+ SafeRelease(drawSurface);
+
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal blit failed, StretchRect returned 0x%X.", result);
+ }
+ }
+
+ if (blitDepth || blitStencil)
+ {
+ const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getDepthOrStencilbuffer();
+ ASSERT(readBuffer);
+
+ RenderTarget9 *readDepthStencil = nullptr;
+ gl::Error error = readBuffer->getRenderTarget(&readDepthStencil);
+ if (error.isError())
+ {
+ return error;
+ }
+ ASSERT(readDepthStencil);
+
+ const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment();
+ ASSERT(drawBuffer);
+
+ RenderTarget9 *drawDepthStencil = nullptr;
+ error = drawBuffer->getRenderTarget(&drawDepthStencil);
+ if (error.isError())
+ {
+ return error;
+ }
+ ASSERT(drawDepthStencil);
+
+ // The getSurface calls do an AddRef so save them until after no errors are possible
+ IDirect3DSurface9* readSurface = readDepthStencil->getSurface();
+ ASSERT(readDepthStencil);
+
+ IDirect3DSurface9* drawSurface = drawDepthStencil->getSurface();
+ ASSERT(drawDepthStencil);
+
+ HRESULT result = device->StretchRect(readSurface, nullptr, drawSurface, nullptr, D3DTEXF_NONE);
+
+ SafeRelease(readSurface);
+ SafeRelease(drawSurface);
+
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal blit failed, StretchRect returned 0x%X.", result);
+ }
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+GLenum Framebuffer9::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const
+{
+ RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTarget);
+ const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(renderTarget9->getD3DFormat());
+ return d3dFormatInfo.info().glInternalFormat;
+}
+
+} // namespace rx
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h
new file mode 100755
index 000000000..8401350b3
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h
@@ -0,0 +1,54 @@
+//
+// Copyright 2014 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.
+//
+
+// Framebuffer9.h: Defines the Framebuffer9 class.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_FRAMBUFFER9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_FRAMBUFFER9_H_
+
+#include "libANGLE/renderer/d3d/FramebufferD3D.h"
+
+namespace rx
+{
+class Renderer9;
+
+class Framebuffer9 : public FramebufferD3D
+{
+ public:
+ Framebuffer9(const gl::FramebufferState &data, Renderer9 *renderer);
+ virtual ~Framebuffer9();
+
+ gl::Error discard(size_t count, const GLenum *attachments) override;
+ gl::Error invalidate(size_t count, const GLenum *attachments) override;
+ gl::Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area) override;
+
+ private:
+ gl::Error clearImpl(ContextImpl *context, const ClearParameters &clearParams) override;
+
+ gl::Error readPixelsImpl(const gl::Rectangle &area,
+ GLenum format,
+ GLenum type,
+ size_t outputPitch,
+ const gl::PixelPackState &pack,
+ uint8_t *pixels) const override;
+
+ gl::Error blitImpl(const gl::Rectangle &sourceArea,
+ const gl::Rectangle &destArea,
+ const gl::Rectangle *scissor,
+ bool blitRenderTarget,
+ bool blitDepth,
+ bool blitStencil,
+ GLenum filter,
+ const gl::Framebuffer *sourceFramebuffer) override;
+
+ GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const override;
+
+ Renderer9 *const mRenderer;
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_FRAMBUFFER9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp
new file mode 100755
index 000000000..ad2c41584
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp
@@ -0,0 +1,822 @@
+//
+// Copyright (c) 2002-2012 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.
+//
+
+// Image9.cpp: Implements the rx::Image9 class, which acts as the interface to
+// the actual underlying surfaces of a Texture.
+
+#include "libANGLE/renderer/d3d/d3d9/Image9.h"
+#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
+#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
+#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/Framebuffer.h"
+#include "libANGLE/FramebufferAttachment.h"
+#include "libANGLE/Renderbuffer.h"
+#include "common/utilities.h"
+
+namespace rx
+{
+
+Image9::Image9(Renderer9 *renderer)
+{
+ mSurface = NULL;
+ mRenderer = NULL;
+
+ mD3DPool = D3DPOOL_SYSTEMMEM;
+ mD3DFormat = D3DFMT_UNKNOWN;
+
+ mRenderer = renderer;
+}
+
+Image9::~Image9()
+{
+ SafeRelease(mSurface);
+}
+
+gl::Error Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface)
+{
+ D3DSURFACE_DESC destDesc;
+ HRESULT result = destSurface->GetDesc(&destDesc);
+ ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the source surface description for mipmap generation, result: 0x%X.", result);
+ }
+
+ D3DSURFACE_DESC sourceDesc;
+ result = sourceSurface->GetDesc(&sourceDesc);
+ ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the destination surface description for mipmap generation, result: 0x%X.", result);
+ }
+
+ ASSERT(sourceDesc.Format == destDesc.Format);
+ ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width);
+ ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height);
+
+ const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(sourceDesc.Format);
+ ASSERT(d3dFormatInfo.info().mipGenerationFunction != NULL);
+
+ D3DLOCKED_RECT sourceLocked = {0};
+ result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY);
+ ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the source surface for mipmap generation, result: 0x%X.", result);
+ }
+
+ D3DLOCKED_RECT destLocked = {0};
+ result = destSurface->LockRect(&destLocked, NULL, 0);
+ ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ sourceSurface->UnlockRect();
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the destination surface for mipmap generation, result: 0x%X.", result);
+ }
+
+ const uint8_t *sourceData = reinterpret_cast<const uint8_t*>(sourceLocked.pBits);
+ uint8_t *destData = reinterpret_cast<uint8_t*>(destLocked.pBits);
+
+ ASSERT(sourceData && destData);
+
+ d3dFormatInfo.info().mipGenerationFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData,
+ sourceLocked.Pitch, 0, destData, destLocked.Pitch,
+ 0);
+
+ destSurface->UnlockRect();
+ sourceSurface->UnlockRect();
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Image9::generateMipmap(Image9 *dest, Image9 *source)
+{
+ IDirect3DSurface9 *sourceSurface = NULL;
+ gl::Error error = source->getSurface(&sourceSurface);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ IDirect3DSurface9 *destSurface = NULL;
+ error = dest->getSurface(&destSurface);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ error = generateMip(destSurface, sourceSurface);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ dest->markDirty();
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source)
+{
+ D3DLOCKED_RECT sourceLock = {0};
+ D3DLOCKED_RECT destLock = {0};
+
+ HRESULT result;
+
+ result = source->LockRect(&sourceLock, NULL, 0);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result);
+ }
+
+ result = dest->LockRect(&destLock, NULL, 0);
+ if (FAILED(result))
+ {
+ source->UnlockRect();
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result);
+ }
+
+ ASSERT(sourceLock.pBits && destLock.pBits);
+
+ D3DSURFACE_DESC desc;
+ source->GetDesc(&desc);
+
+ const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
+ unsigned int rows = desc.Height / d3dFormatInfo.blockHeight;
+
+ unsigned int bytes = d3d9::ComputeBlockSize(desc.Format, desc.Width, d3dFormatInfo.blockHeight);
+ ASSERT(bytes <= static_cast<unsigned int>(sourceLock.Pitch) &&
+ bytes <= static_cast<unsigned int>(destLock.Pitch));
+
+ for(unsigned int i = 0; i < rows; i++)
+ {
+ memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes);
+ }
+
+ source->UnlockRect();
+ dest->UnlockRect();
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+bool Image9::redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease)
+{
+ // 3D textures are not supported by the D3D9 backend.
+ ASSERT(size.depth <= 1);
+
+ // Only 2D and cube texture are supported by the D3D9 backend.
+ ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP);
+
+ if (mWidth != size.width ||
+ mHeight != size.height ||
+ mDepth != size.depth ||
+ mInternalFormat != internalformat ||
+ forceRelease)
+ {
+ mWidth = size.width;
+ mHeight = size.height;
+ mDepth = size.depth;
+ mInternalFormat = internalformat;
+
+ // compute the d3d format that will be used
+ const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(internalformat);
+ mD3DFormat = d3d9FormatInfo.texFormat;
+ mRenderable = (d3d9FormatInfo.renderFormat != D3DFMT_UNKNOWN);
+
+ SafeRelease(mSurface);
+ mDirty = (d3d9FormatInfo.dataInitializerFunction != NULL);
+
+ return true;
+ }
+
+ return false;
+}
+
+gl::Error Image9::createSurface()
+{
+ if (mSurface)
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ IDirect3DTexture9 *newTexture = NULL;
+ IDirect3DSurface9 *newSurface = NULL;
+ const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM;
+ const D3DFORMAT d3dFormat = getD3DFormat();
+
+ if (mWidth != 0 && mHeight != 0)
+ {
+ int levelToFetch = 0;
+ GLsizei requestWidth = mWidth;
+ GLsizei requestHeight = mHeight;
+ d3d9::MakeValidSize(true, d3dFormat, &requestWidth, &requestHeight, &levelToFetch);
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ HRESULT result = device->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, 0, d3dFormat,
+ poolToUse, &newTexture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create image surface, result: 0x%X.", result);
+ }
+
+ newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
+ SafeRelease(newTexture);
+
+ const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat);
+ if (d3dFormatInfo.dataInitializerFunction != NULL)
+ {
+ RECT entireRect;
+ entireRect.left = 0;
+ entireRect.right = mWidth;
+ entireRect.top = 0;
+ entireRect.bottom = mHeight;
+
+ D3DLOCKED_RECT lockedRect;
+ result = newSurface->LockRect(&lockedRect, &entireRect, 0);
+ ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock image surface, result: 0x%X.", result);
+ }
+
+ d3dFormatInfo.dataInitializerFunction(mWidth, mHeight, 1, reinterpret_cast<uint8_t*>(lockedRect.pBits),
+ lockedRect.Pitch, 0);
+
+ result = newSurface->UnlockRect();
+ ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock image surface, result: 0x%X.", result);
+ }
+ }
+ }
+
+ mSurface = newSurface;
+ mDirty = false;
+ mD3DPool = poolToUse;
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT &rect)
+{
+ gl::Error error = createSurface();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ if (mSurface)
+ {
+ HRESULT result = mSurface->LockRect(lockedRect, &rect, 0);
+ ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock image surface, result: 0x%X.", result);
+ }
+
+ mDirty = true;
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+void Image9::unlock()
+{
+ if (mSurface)
+ {
+ HRESULT result = mSurface->UnlockRect();
+ ASSERT(SUCCEEDED(result));
+ }
+}
+
+D3DFORMAT Image9::getD3DFormat() const
+{
+ // this should only happen if the image hasn't been redefined first
+ // which would be a bug by the caller
+ ASSERT(mD3DFormat != D3DFMT_UNKNOWN);
+
+ return mD3DFormat;
+}
+
+bool Image9::isDirty() const
+{
+ // Make sure to that this image is marked as dirty even if the staging texture hasn't been created yet
+ // if initialization is required before use.
+ return (mSurface || d3d9::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL) && mDirty;
+}
+
+gl::Error Image9::getSurface(IDirect3DSurface9 **outSurface)
+{
+ gl::Error error = createSurface();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ *outSurface = mSurface;
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Image9::setManagedSurface2D(TextureStorage *storage, int level)
+{
+ IDirect3DSurface9 *surface = NULL;
+ TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
+ gl::Error error = storage9->getSurfaceLevel(GL_TEXTURE_2D, level, false, &surface);
+ if (error.isError())
+ {
+ return error;
+ }
+ return setManagedSurface(surface);
+}
+
+gl::Error Image9::setManagedSurfaceCube(TextureStorage *storage, int face, int level)
+{
+ IDirect3DSurface9 *surface = NULL;
+ TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
+ gl::Error error =
+ storage9->getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false, &surface);
+ if (error.isError())
+ {
+ return error;
+ }
+ return setManagedSurface(surface);
+}
+
+gl::Error Image9::setManagedSurface(IDirect3DSurface9 *surface)
+{
+ D3DSURFACE_DESC desc;
+ surface->GetDesc(&desc);
+ ASSERT(desc.Pool == D3DPOOL_MANAGED);
+
+ if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight)
+ {
+ if (mSurface)
+ {
+ gl::Error error = copyLockableSurfaces(surface, mSurface);
+ SafeRelease(mSurface);
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+
+ mSurface = surface;
+ mD3DPool = desc.Pool;
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Image9::copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region)
+{
+ gl::Error error = createSurface();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
+
+ IDirect3DSurface9 *destSurface = NULL;
+
+ if (index.type == GL_TEXTURE_2D)
+ {
+ error = storage9->getSurfaceLevel(GL_TEXTURE_2D, index.mipIndex, true, &destSurface);
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+ else
+ {
+ ASSERT(gl::IsCubeMapTextureTarget(index.type));
+ error = storage9->getSurfaceLevel(index.type, index.mipIndex, true, &destSurface);
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+
+ error = copyToSurface(destSurface, region);
+ SafeRelease(destSurface);
+ return error;
+}
+
+gl::Error Image9::copyToSurface(IDirect3DSurface9 *destSurface, const gl::Box &area)
+{
+ ASSERT(area.width > 0 && area.height > 0 && area.depth == 1);
+ ASSERT(destSurface);
+
+ IDirect3DSurface9 *sourceSurface = NULL;
+ gl::Error error = getSurface(&sourceSurface);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ASSERT(sourceSurface && sourceSurface != destSurface);
+
+ RECT rect;
+ rect.left = area.x;
+ rect.top = area.y;
+ rect.right = area.x + area.width;
+ rect.bottom = area.y + area.height;
+
+ POINT point = {rect.left, rect.top};
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ if (mD3DPool == D3DPOOL_MANAGED)
+ {
+ D3DSURFACE_DESC desc;
+ sourceSurface->GetDesc(&desc);
+
+ IDirect3DSurface9 *surf = 0;
+ HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal CreateOffscreenPlainSurface call failed, result: 0x%X.", result);
+ }
+
+ copyLockableSurfaces(surf, sourceSurface);
+ result = device->UpdateSurface(surf, &rect, destSurface, &point);
+ SafeRelease(surf);
+ ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal UpdateSurface call failed, result: 0x%X.", result);
+ }
+ }
+ else
+ {
+ // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools
+ HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point);
+ ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal UpdateSurface call failed, result: 0x%X.", result);
+ }
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
+// into the target pixel rectangle.
+gl::Error Image9::loadData(const gl::Box &area,
+ const gl::PixelUnpackState &unpack,
+ GLenum inputType,
+ const void *input,
+ bool applySkipImages)
+{
+ // 3D textures are not supported by the D3D9 backend.
+ ASSERT(area.z == 0 && area.depth == 1);
+ ASSERT(getSizedInputFormat(inputType) == mInternalFormat);
+ const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
+ GLuint inputRowPitch = 0;
+ ANGLE_TRY_RESULT(
+ formatInfo.computeRowPitch(area.width, unpack.alignment, unpack.rowLength),
+ inputRowPitch);
+ ASSERT(!applySkipImages);
+ ASSERT(unpack.skipPixels == 0);
+ ASSERT(unpack.skipRows == 0);
+
+ const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat);
+ ASSERT(d3dFormatInfo.loadFunction != NULL);
+
+ RECT lockRect =
+ {
+ area.x, area.y,
+ area.x + area.width, area.y + area.height
+ };
+
+ D3DLOCKED_RECT locked;
+ gl::Error error = lock(&locked, lockRect);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ d3dFormatInfo.loadFunction(area.width, area.height, area.depth,
+ reinterpret_cast<const uint8_t *>(input), inputRowPitch, 0,
+ reinterpret_cast<uint8_t *>(locked.pBits), locked.Pitch, 0);
+
+ unlock();
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Image9::loadCompressedData(const gl::Box &area, const void *input)
+{
+ // 3D textures are not supported by the D3D9 backend.
+ ASSERT(area.z == 0 && area.depth == 1);
+
+ const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
+ GLsizei inputRowPitch = 0;
+ ANGLE_TRY_RESULT(formatInfo.computeRowPitch(area.width, 1, 0), inputRowPitch);
+ GLsizei inputDepthPitch = 0;
+ ANGLE_TRY_RESULT(formatInfo.computeDepthPitch(area.height, 0, inputDepthPitch),
+ inputDepthPitch);
+
+ const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat);
+
+ ASSERT(area.x % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockWidth == 0);
+ ASSERT(area.y % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockHeight == 0);
+
+ ASSERT(d3d9FormatInfo.loadFunction != NULL);
+
+ RECT lockRect =
+ {
+ area.x, area.y,
+ area.x + area.width, area.y + area.height
+ };
+
+ D3DLOCKED_RECT locked;
+ gl::Error error = lock(&locked, lockRect);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ d3d9FormatInfo.loadFunction(area.width, area.height, area.depth,
+ reinterpret_cast<const uint8_t*>(input), inputRowPitch, inputDepthPitch,
+ reinterpret_cast<uint8_t*>(locked.pBits), locked.Pitch, 0);
+
+ unlock();
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
+gl::Error Image9::copyFromRTInternal(const gl::Offset &destOffset,
+ const gl::Rectangle &sourceArea,
+ RenderTargetD3D *source)
+{
+ ASSERT(source);
+
+ // ES3.0 only behaviour to copy into a 3d texture
+ ASSERT(destOffset.z == 0);
+
+ RenderTarget9 *renderTarget = GetAs<RenderTarget9>(source);
+
+ IDirect3DSurface9 *surface = renderTarget->getSurface();
+ ASSERT(surface);
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ IDirect3DSurface9 *renderTargetData = NULL;
+ D3DSURFACE_DESC description;
+ surface->GetDesc(&description);
+
+ HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
+
+ if (FAILED(result))
+ {
+ SafeRelease(surface);
+ return gl::Error(GL_OUT_OF_MEMORY, "Could not create matching destination surface, result: 0x%X.", result);
+ }
+
+ result = device->GetRenderTargetData(surface, renderTargetData);
+
+ if (FAILED(result))
+ {
+ SafeRelease(renderTargetData);
+ SafeRelease(surface);
+ return gl::Error(GL_OUT_OF_MEMORY, "GetRenderTargetData unexpectedly failed, result: 0x%X.", result);
+ }
+
+ int width = sourceArea.width;
+ int height = sourceArea.height;
+
+ RECT sourceRect = { sourceArea.x, sourceArea.y, sourceArea.x + width, sourceArea.y + height };
+ RECT destRect = { destOffset.x, destOffset.y, destOffset.x + width, destOffset.y + height };
+
+ D3DLOCKED_RECT sourceLock = {0};
+ result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
+
+ if (FAILED(result))
+ {
+ SafeRelease(renderTargetData);
+ SafeRelease(surface);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the source surface (rectangle might be invalid), result: 0x%X.", result);
+ }
+
+ D3DLOCKED_RECT destLock = {0};
+ gl::Error error = lock(&destLock, destRect);
+ if (error.isError())
+ {
+ renderTargetData->UnlockRect();
+ SafeRelease(renderTargetData);
+ SafeRelease(surface);
+ return error;
+ }
+
+ ASSERT(destLock.pBits && sourceLock.pBits);
+
+ unsigned char *sourcePixels = (unsigned char*)sourceLock.pBits;
+ unsigned char *destPixels = (unsigned char*)destLock.pBits;
+
+ switch (description.Format)
+ {
+ case D3DFMT_X8R8G8B8:
+ case D3DFMT_A8R8G8B8:
+ switch (getD3DFormat())
+ {
+ case D3DFMT_X8R8G8B8:
+ case D3DFMT_A8R8G8B8:
+ for (int y = 0; y < height; y++)
+ {
+ memcpy(destPixels, sourcePixels, 4 * width);
+ sourcePixels += sourceLock.Pitch;
+ destPixels += destLock.Pitch;
+ }
+ break;
+ case D3DFMT_L8:
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ destPixels[x] = sourcePixels[x * 4 + 2];
+ }
+ sourcePixels += sourceLock.Pitch;
+ destPixels += destLock.Pitch;
+ }
+ break;
+ case D3DFMT_A8L8:
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ destPixels[x * 2 + 0] = sourcePixels[x * 4 + 2];
+ destPixels[x * 2 + 1] = sourcePixels[x * 4 + 3];
+ }
+ sourcePixels += sourceLock.Pitch;
+ destPixels += destLock.Pitch;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+ case D3DFMT_R5G6B5:
+ switch (getD3DFormat())
+ {
+ case D3DFMT_X8R8G8B8:
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ unsigned short rgb = ((unsigned short*)sourcePixels)[x];
+ unsigned char red = static_cast<unsigned char>((rgb & 0xF800) >> 8);
+ unsigned char green = static_cast<unsigned char>((rgb & 0x07E0) >> 3);
+ unsigned char blue = static_cast<unsigned char>((rgb & 0x001F) << 3);
+ destPixels[x + 0] = blue | (blue >> 5);
+ destPixels[x + 1] = green | (green >> 6);
+ destPixels[x + 2] = red | (red >> 5);
+ destPixels[x + 3] = 0xFF;
+ }
+ sourcePixels += sourceLock.Pitch;
+ destPixels += destLock.Pitch;
+ }
+ break;
+ case D3DFMT_L8:
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ unsigned char red = sourcePixels[x * 2 + 1] & 0xF8;
+ destPixels[x] = red | (red >> 5);
+ }
+ sourcePixels += sourceLock.Pitch;
+ destPixels += destLock.Pitch;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+ case D3DFMT_A1R5G5B5:
+ switch (getD3DFormat())
+ {
+ case D3DFMT_X8R8G8B8:
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ unsigned short argb = ((unsigned short*)sourcePixels)[x];
+ unsigned char red = static_cast<unsigned char>((argb & 0x7C00) >> 7);
+ unsigned char green = static_cast<unsigned char>((argb & 0x03E0) >> 2);
+ unsigned char blue = static_cast<unsigned char>((argb & 0x001F) << 3);
+ destPixels[x + 0] = blue | (blue >> 5);
+ destPixels[x + 1] = green | (green >> 5);
+ destPixels[x + 2] = red | (red >> 5);
+ destPixels[x + 3] = 0xFF;
+ }
+ sourcePixels += sourceLock.Pitch;
+ destPixels += destLock.Pitch;
+ }
+ break;
+ case D3DFMT_A8R8G8B8:
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ unsigned short argb = ((unsigned short*)sourcePixels)[x];
+ unsigned char red = static_cast<unsigned char>((argb & 0x7C00) >> 7);
+ unsigned char green = static_cast<unsigned char>((argb & 0x03E0) >> 2);
+ unsigned char blue = static_cast<unsigned char>((argb & 0x001F) << 3);
+ unsigned char alpha = (signed short)argb >> 15;
+ destPixels[x + 0] = blue | (blue >> 5);
+ destPixels[x + 1] = green | (green >> 5);
+ destPixels[x + 2] = red | (red >> 5);
+ destPixels[x + 3] = alpha;
+ }
+ sourcePixels += sourceLock.Pitch;
+ destPixels += destLock.Pitch;
+ }
+ break;
+ case D3DFMT_L8:
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ unsigned char red = sourcePixels[x * 2 + 1] & 0x7C;
+ destPixels[x] = (red << 1) | (red >> 4);
+ }
+ sourcePixels += sourceLock.Pitch;
+ destPixels += destLock.Pitch;
+ }
+ break;
+ case D3DFMT_A8L8:
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ unsigned char red = sourcePixels[x * 2 + 1] & 0x7C;
+ destPixels[x * 2 + 0] = (red << 1) | (red >> 4);
+ destPixels[x * 2 + 1] = (signed char)sourcePixels[x * 2 + 1] >> 7;
+ }
+ sourcePixels += sourceLock.Pitch;
+ destPixels += destLock.Pitch;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ unlock();
+ renderTargetData->UnlockRect();
+
+ SafeRelease(renderTargetData);
+ SafeRelease(surface);
+
+ mDirty = true;
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Image9::copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source)
+{
+ RenderTargetD3D *renderTarget = nullptr;
+ gl::Error error = source->getRenderTarget(imageIndex, &renderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ gl::Rectangle sourceArea(0, 0, mWidth, mHeight);
+ return copyFromRTInternal(gl::Offset(), sourceArea, renderTarget);
+}
+
+gl::Error Image9::copyFromFramebuffer(const gl::Offset &destOffset,
+ const gl::Rectangle &sourceArea,
+ const gl::Framebuffer *source)
+{
+ const gl::FramebufferAttachment *srcAttachment = source->getReadColorbuffer();
+ ASSERT(srcAttachment);
+
+ RenderTargetD3D *renderTarget = NULL;
+ gl::Error error = srcAttachment->getRenderTarget(&renderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ASSERT(renderTarget);
+ return copyFromRTInternal(destOffset, sourceArea, renderTarget);
+}
+
+} // namespace rx
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h
new file mode 100755
index 000000000..068a67fc9
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h
@@ -0,0 +1,80 @@
+//
+// Copyright (c) 2002-2014 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.
+//
+
+// Image9.h: Defines the rx::Image9 class, which acts as the interface to
+// the actual underlying surfaces of a Texture.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_IMAGE9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_IMAGE9_H_
+
+#include "libANGLE/renderer/d3d/ImageD3D.h"
+#include "common/debug.h"
+
+namespace gl
+{
+class Framebuffer;
+}
+
+namespace rx
+{
+class Renderer9;
+
+class Image9 : public ImageD3D
+{
+ public:
+ Image9(Renderer9 *renderer);
+ ~Image9();
+
+ static gl::Error generateMipmap(Image9 *dest, Image9 *source);
+ static gl::Error generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface);
+ static gl::Error copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source);
+
+ bool redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) override;
+
+ D3DFORMAT getD3DFormat() const;
+
+ virtual bool isDirty() const;
+
+ virtual gl::Error setManagedSurface2D(TextureStorage *storage, int level);
+ virtual gl::Error setManagedSurfaceCube(TextureStorage *storage, int face, int level);
+ virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region);
+
+ gl::Error loadData(const gl::Box &area,
+ const gl::PixelUnpackState &unpack,
+ GLenum type,
+ const void *input,
+ bool applySkipImages) override;
+ gl::Error loadCompressedData(const gl::Box &area, const void *input) override;
+
+ gl::Error copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source) override;
+ gl::Error copyFromFramebuffer(const gl::Offset &destOffset,
+ const gl::Rectangle &sourceArea,
+ const gl::Framebuffer *source) override;
+
+ private:
+ gl::Error getSurface(IDirect3DSurface9 **outSurface);
+
+ gl::Error createSurface();
+ gl::Error setManagedSurface(IDirect3DSurface9 *surface);
+ gl::Error copyToSurface(IDirect3DSurface9 *dest, const gl::Box &area);
+
+ gl::Error lock(D3DLOCKED_RECT *lockedRect, const RECT &rect);
+ void unlock();
+
+ gl::Error copyFromRTInternal(const gl::Offset &destOffset,
+ const gl::Rectangle &sourceArea,
+ RenderTargetD3D *source);
+
+ Renderer9 *mRenderer;
+
+ D3DPOOL mD3DPool; // can only be D3DPOOL_SYSTEMMEM or D3DPOOL_MANAGED since it needs to be lockable.
+ D3DFORMAT mD3DFormat;
+
+ IDirect3DSurface9 *mSurface;
+};
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_IMAGE9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp
new file mode 100755
index 000000000..40152df25
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp
@@ -0,0 +1,167 @@
+//
+// Copyright (c) 2002-2014 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.
+//
+
+// Indexffer9.cpp: Defines the D3D9 IndexBuffer implementation.
+
+#include "libANGLE/renderer/d3d/d3d9/IndexBuffer9.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+
+namespace rx
+{
+
+IndexBuffer9::IndexBuffer9(Renderer9 *const renderer) : mRenderer(renderer)
+{
+ mIndexBuffer = NULL;
+ mBufferSize = 0;
+ mIndexType = 0;
+ mDynamic = false;
+}
+
+IndexBuffer9::~IndexBuffer9()
+{
+ SafeRelease(mIndexBuffer);
+}
+
+gl::Error IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic)
+{
+ SafeRelease(mIndexBuffer);
+
+ updateSerial();
+
+ if (bufferSize > 0)
+ {
+ D3DFORMAT format = D3DFMT_UNKNOWN;
+ if (indexType == GL_UNSIGNED_SHORT || indexType == GL_UNSIGNED_BYTE)
+ {
+ format = D3DFMT_INDEX16;
+ }
+ else if (indexType == GL_UNSIGNED_INT)
+ {
+ ASSERT(mRenderer->getNativeExtensions().elementIndexUint);
+ format = D3DFMT_INDEX32;
+ }
+ else UNREACHABLE();
+
+ DWORD usageFlags = D3DUSAGE_WRITEONLY;
+ if (dynamic)
+ {
+ usageFlags |= D3DUSAGE_DYNAMIC;
+ }
+
+ HRESULT result = mRenderer->createIndexBuffer(bufferSize, usageFlags, format, &mIndexBuffer);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal index buffer of size, %lu.", bufferSize);
+ }
+ }
+
+ mBufferSize = bufferSize;
+ mIndexType = indexType;
+ mDynamic = dynamic;
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error IndexBuffer9::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory)
+{
+ if (!mIndexBuffer)
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized.");
+ }
+
+ DWORD lockFlags = mDynamic ? D3DLOCK_NOOVERWRITE : 0;
+
+ void *mapPtr = NULL;
+ HRESULT result = mIndexBuffer->Lock(offset, size, &mapPtr, lockFlags);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal index buffer, HRESULT: 0x%08x.", result);
+ }
+
+ *outMappedMemory = mapPtr;
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error IndexBuffer9::unmapBuffer()
+{
+ if (!mIndexBuffer)
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized.");
+ }
+
+ HRESULT result = mIndexBuffer->Unlock();
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal index buffer, HRESULT: 0x%08x.", result);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+GLenum IndexBuffer9::getIndexType() const
+{
+ return mIndexType;
+}
+
+unsigned int IndexBuffer9::getBufferSize() const
+{
+ return mBufferSize;
+}
+
+gl::Error IndexBuffer9::setSize(unsigned int bufferSize, GLenum indexType)
+{
+ if (bufferSize > mBufferSize || indexType != mIndexType)
+ {
+ return initialize(bufferSize, indexType, mDynamic);
+ }
+ else
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+}
+
+gl::Error IndexBuffer9::discard()
+{
+ if (!mIndexBuffer)
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized.");
+ }
+
+ void *dummy;
+ HRESULT result;
+
+ result = mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal index buffer, HRESULT: 0x%08x.", result);
+ }
+
+ result = mIndexBuffer->Unlock();
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal index buffer, HRESULT: 0x%08x.", result);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+D3DFORMAT IndexBuffer9::getIndexFormat() const
+{
+ switch (mIndexType)
+ {
+ case GL_UNSIGNED_BYTE: return D3DFMT_INDEX16;
+ case GL_UNSIGNED_SHORT: return D3DFMT_INDEX16;
+ case GL_UNSIGNED_INT: return D3DFMT_INDEX32;
+ default: UNREACHABLE(); return D3DFMT_UNKNOWN;
+ }
+}
+
+IDirect3DIndexBuffer9 * IndexBuffer9::getBuffer() const
+{
+ return mIndexBuffer;
+}
+
+}
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h
new file mode 100755
index 000000000..ba03ba703
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h
@@ -0,0 +1,49 @@
+//
+// Copyright (c) 2002-2012 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.
+//
+
+// Indexffer9.h: Defines the D3D9 IndexBuffer implementation.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_INDEXBUFFER9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_INDEXBUFFER9_H_
+
+#include "libANGLE/renderer/d3d/IndexBuffer.h"
+
+namespace rx
+{
+class Renderer9;
+
+class IndexBuffer9 : public IndexBuffer
+{
+ public:
+ explicit IndexBuffer9(Renderer9 *const renderer);
+ virtual ~IndexBuffer9();
+
+ virtual gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic);
+
+ virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory);
+ virtual gl::Error unmapBuffer();
+
+ virtual GLenum getIndexType() const;
+ virtual unsigned int getBufferSize() const;
+ virtual gl::Error setSize(unsigned int bufferSize, GLenum indexType);
+
+ virtual gl::Error discard();
+
+ D3DFORMAT getIndexFormat() const;
+ IDirect3DIndexBuffer9 *getBuffer() const;
+
+ private:
+ Renderer9 *const mRenderer;
+
+ IDirect3DIndexBuffer9 *mIndexBuffer;
+ unsigned int mBufferSize;
+ GLenum mIndexType;
+ bool mDynamic;
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_INDEXBUFFER9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp
new file mode 100755
index 000000000..388b8aa16
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp
@@ -0,0 +1,39 @@
+//
+// Copyright (c) 2016 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.
+//
+
+// NativeWindow9.cpp: Defines NativeWindow9, a class for managing and
+// performing operations on an EGLNativeWindowType for the D3D9 renderer.
+
+#include "libANGLE/renderer/d3d/d3d9/NativeWindow9.h"
+
+namespace rx
+{
+NativeWindow9::NativeWindow9(EGLNativeWindowType window) : NativeWindowD3D(window)
+{
+}
+
+bool NativeWindow9::initialize()
+{
+ return true;
+}
+
+bool NativeWindow9::getClientRect(LPRECT rect) const
+{
+ return GetClientRect(getNativeWindow(), rect) == TRUE;
+}
+
+bool NativeWindow9::isIconic() const
+{
+ return IsIconic(getNativeWindow()) == TRUE;
+}
+
+// static
+bool NativeWindow9::IsValidNativeWindow(EGLNativeWindowType window)
+{
+ return IsWindow(window) == TRUE;
+}
+
+} // namespace rx
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h
new file mode 100755
index 000000000..a56b08dc8
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h
@@ -0,0 +1,35 @@
+//
+// Copyright (c) 2016 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.
+//
+
+// NativeWindow9.h: Defines NativeWindow9, a class for managing and
+// performing operations on an EGLNativeWindowType for the D3D9 renderer.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_NATIVEWINDOW9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_NATIVEWINDOW9_H_
+
+#include "common/debug.h"
+#include "common/platform.h"
+
+#include "libANGLE/renderer/d3d/NativeWindowD3D.h"
+
+namespace rx
+{
+
+class NativeWindow9 : public NativeWindowD3D
+{
+ public:
+ explicit NativeWindow9(EGLNativeWindowType window);
+
+ bool initialize() override;
+ bool getClientRect(LPRECT rect) const override;
+ bool isIconic() const override;
+
+ static bool IsValidNativeWindow(EGLNativeWindowType window);
+};
+
+} // namespace rx
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_NATIVEWINDOW9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp
new file mode 100755
index 000000000..9e5a90a2f
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp
@@ -0,0 +1,189 @@
+//
+// Copyright (c) 2013 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.
+//
+
+// Query9.cpp: Defines the rx::Query9 class which implements rx::QueryImpl.
+
+#include "libANGLE/renderer/d3d/d3d9/Query9.h"
+#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+
+#include <GLES2/gl2ext.h>
+
+namespace rx
+{
+Query9::Query9(Renderer9 *renderer, GLenum type)
+ : QueryImpl(type),
+ mResult(GL_FALSE),
+ mQueryFinished(false),
+ mRenderer(renderer),
+ mQuery(NULL)
+{
+}
+
+Query9::~Query9()
+{
+ SafeRelease(mQuery);
+}
+
+gl::Error Query9::begin()
+{
+ D3DQUERYTYPE d3dQueryType = gl_d3d9::ConvertQueryType(getType());
+ if (mQuery == nullptr)
+ {
+ HRESULT result = mRenderer->getDevice()->CreateQuery(d3dQueryType, &mQuery);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", result);
+ }
+ }
+
+ if (d3dQueryType != D3DQUERYTYPE_EVENT)
+ {
+ HRESULT result = mQuery->Issue(D3DISSUE_BEGIN);
+ ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to begin internal query, result: 0x%X.",
+ result);
+ }
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Query9::end()
+{
+ ASSERT(mQuery);
+
+ HRESULT result = mQuery->Issue(D3DISSUE_END);
+ ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to end internal query, result: 0x%X.", result);
+ }
+
+ mQueryFinished = false;
+ mResult = GL_FALSE;
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Query9::queryCounter()
+{
+ UNIMPLEMENTED();
+ return gl::Error(GL_INVALID_OPERATION, "Unimplemented");
+}
+
+template <typename T>
+gl::Error Query9::getResultBase(T *params)
+{
+ while (!mQueryFinished)
+ {
+ gl::Error error = testQuery();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ if (!mQueryFinished)
+ {
+ Sleep(0);
+ }
+ }
+
+ ASSERT(mQueryFinished);
+ *params = static_cast<T>(mResult);
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Query9::getResult(GLint *params)
+{
+ return getResultBase(params);
+}
+
+gl::Error Query9::getResult(GLuint *params)
+{
+ return getResultBase(params);
+}
+
+gl::Error Query9::getResult(GLint64 *params)
+{
+ return getResultBase(params);
+}
+
+gl::Error Query9::getResult(GLuint64 *params)
+{
+ return getResultBase(params);
+}
+
+gl::Error Query9::isResultAvailable(bool *available)
+{
+ gl::Error error = testQuery();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ *available = mQueryFinished;
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Query9::testQuery()
+{
+ if (!mQueryFinished)
+ {
+ ASSERT(mQuery);
+
+ HRESULT result = S_OK;
+ switch (getType())
+ {
+ case GL_ANY_SAMPLES_PASSED_EXT:
+ case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
+ {
+ DWORD numPixels = 0;
+ result = mQuery->GetData(&numPixels, sizeof(numPixels), D3DGETDATA_FLUSH);
+ if (result == S_OK)
+ {
+ mQueryFinished = true;
+ mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE;
+ }
+ break;
+ }
+
+ case GL_COMMANDS_COMPLETED_CHROMIUM:
+ {
+ BOOL completed = FALSE;
+ result = mQuery->GetData(&completed, sizeof(completed), D3DGETDATA_FLUSH);
+ if (result == S_OK)
+ {
+ mQueryFinished = true;
+ mResult = (completed == TRUE) ? GL_TRUE : GL_FALSE;
+ }
+ break;
+ }
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ if (d3d9::isDeviceLostError(result))
+ {
+ mRenderer->notifyDeviceLost();
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost.");
+ }
+ else if (mRenderer->testDeviceLost())
+ {
+ mRenderer->notifyDeviceLost();
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost.");
+ }
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+}
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h
new file mode 100755
index 000000000..9d17711a0
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h
@@ -0,0 +1,48 @@
+//
+// Copyright (c) 2013 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.
+//
+
+// Query9.h: Defines the rx::Query9 class which implements rx::QueryImpl.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_QUERY9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_QUERY9_H_
+
+#include "libANGLE/renderer/QueryImpl.h"
+
+namespace rx
+{
+class Renderer9;
+
+class Query9 : public QueryImpl
+{
+ public:
+ Query9(Renderer9 *renderer, GLenum type);
+ virtual ~Query9();
+
+ virtual gl::Error begin();
+ virtual gl::Error end();
+ virtual gl::Error queryCounter();
+ virtual gl::Error getResult(GLint *params);
+ virtual gl::Error getResult(GLuint *params);
+ virtual gl::Error getResult(GLint64 *params);
+ virtual gl::Error getResult(GLuint64 *params);
+ virtual gl::Error isResultAvailable(bool *available);
+
+ private:
+ gl::Error testQuery();
+
+ template <typename T>
+ gl::Error getResultBase(T *params);
+
+ GLuint64 mResult;
+ bool mQueryFinished;
+
+ Renderer9 *mRenderer;
+ IDirect3DQuery9 *mQuery;
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_QUERY9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp
new file mode 100755
index 000000000..3e54c27f4
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp
@@ -0,0 +1,163 @@
+//
+// Copyright (c) 2012-2014 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.
+//
+
+// RenderTarget9.cpp: Implements a D3D9-specific wrapper for IDirect3DSurface9
+// pointers retained by renderbuffers.
+
+#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
+#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h"
+#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
+
+namespace rx
+{
+
+// TODO: AddRef the incoming surface to take ownership instead of expecting that its ref is being given.
+TextureRenderTarget9::TextureRenderTarget9(IDirect3DBaseTexture9 *texture,
+ size_t textureLevel,
+ IDirect3DSurface9 *surface,
+ GLenum internalFormat,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLsizei samples)
+ : mWidth(width),
+ mHeight(height),
+ mDepth(depth),
+ mInternalFormat(internalFormat),
+ mD3DFormat(D3DFMT_UNKNOWN),
+ mSamples(samples),
+ mTexture(texture),
+ mTextureLevel(textureLevel),
+ mRenderTarget(surface)
+{
+ ASSERT(mDepth == 1);
+
+ if (mRenderTarget)
+ {
+ D3DSURFACE_DESC description;
+ mRenderTarget->GetDesc(&description);
+ mD3DFormat = description.Format;
+ }
+}
+
+TextureRenderTarget9::~TextureRenderTarget9()
+{
+ SafeRelease(mTexture);
+ SafeRelease(mRenderTarget);
+}
+
+GLsizei TextureRenderTarget9::getWidth() const
+{
+ return mWidth;
+}
+
+GLsizei TextureRenderTarget9::getHeight() const
+{
+ return mHeight;
+}
+
+GLsizei TextureRenderTarget9::getDepth() const
+{
+ return mDepth;
+}
+
+GLenum TextureRenderTarget9::getInternalFormat() const
+{
+ return mInternalFormat;
+}
+
+GLsizei TextureRenderTarget9::getSamples() const
+{
+ return mSamples;
+}
+
+IDirect3DBaseTexture9 *TextureRenderTarget9::getTexture() const
+{
+ return mTexture;
+}
+
+size_t TextureRenderTarget9::getTextureLevel() const
+{
+ return mTextureLevel;
+}
+
+IDirect3DSurface9 *TextureRenderTarget9::getSurface() const
+{
+ // Caller is responsible for releasing the returned surface reference.
+ // TODO: remove the AddRef to match RenderTarget11
+ if (mRenderTarget)
+ {
+ mRenderTarget->AddRef();
+ }
+
+ return mRenderTarget;
+}
+
+D3DFORMAT TextureRenderTarget9::getD3DFormat() const
+{
+ return mD3DFormat;
+}
+
+SurfaceRenderTarget9::SurfaceRenderTarget9(SwapChain9 *swapChain, bool depth)
+ : mSwapChain(swapChain),
+ mDepth(depth)
+{
+}
+
+SurfaceRenderTarget9::~SurfaceRenderTarget9()
+{
+}
+
+GLsizei SurfaceRenderTarget9::getWidth() const
+{
+ return mSwapChain->getWidth();
+}
+
+GLsizei SurfaceRenderTarget9::getHeight() const
+{
+ return mSwapChain->getHeight();
+}
+
+GLsizei SurfaceRenderTarget9::getDepth() const
+{
+ return 1;
+}
+
+GLenum SurfaceRenderTarget9::getInternalFormat() const
+{
+ return (mDepth ? mSwapChain->getDepthBufferInternalFormat()
+ : mSwapChain->getRenderTargetInternalFormat());
+}
+
+GLsizei SurfaceRenderTarget9::getSamples() const
+{
+ // Our EGL surfaces do not support multisampling.
+ return 0;
+}
+
+IDirect3DSurface9 *SurfaceRenderTarget9::getSurface() const
+{
+ return (mDepth ? mSwapChain->getDepthStencil() : mSwapChain->getRenderTarget());
+}
+
+IDirect3DBaseTexture9 *SurfaceRenderTarget9::getTexture() const
+{
+ return (mDepth ? nullptr : mSwapChain->getOffscreenTexture());
+}
+
+size_t SurfaceRenderTarget9::getTextureLevel() const
+{
+ return 0;
+}
+
+D3DFORMAT SurfaceRenderTarget9::getD3DFormat() const
+{
+ return d3d9::GetTextureFormatInfo(getInternalFormat()).texFormat;
+}
+
+}
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h
new file mode 100755
index 000000000..f19c54de7
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h
@@ -0,0 +1,98 @@
+//
+// Copyright (c) 2012 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.
+//
+
+// RenderTarget9.h: Defines a D3D9-specific wrapper for IDirect3DSurface9 pointers
+// retained by Renderbuffers.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_RENDERTARGET9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_RENDERTARGET9_H_
+
+#include "libANGLE/renderer/d3d/RenderTargetD3D.h"
+
+namespace rx
+{
+class Renderer9;
+class SwapChain9;
+
+class RenderTarget9 : public RenderTargetD3D
+{
+ public:
+ RenderTarget9() { }
+ virtual ~RenderTarget9() { }
+ // Retrieve the texture that backs this render target, may be null for swap chain render
+ // targets.
+ virtual IDirect3DBaseTexture9 *getTexture() const = 0;
+ virtual size_t getTextureLevel() const = 0;
+
+ virtual IDirect3DSurface9 *getSurface() const = 0;
+
+ virtual D3DFORMAT getD3DFormat() const = 0;
+};
+
+class TextureRenderTarget9 : public RenderTarget9
+{
+ public:
+ TextureRenderTarget9(IDirect3DBaseTexture9 *texture,
+ size_t textureLevel,
+ IDirect3DSurface9 *surface,
+ GLenum internalFormat,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLsizei samples);
+ virtual ~TextureRenderTarget9();
+
+ GLsizei getWidth() const override;
+ GLsizei getHeight() const override;
+ GLsizei getDepth() const override;
+ GLenum getInternalFormat() const override;
+ GLsizei getSamples() const override;
+
+ IDirect3DBaseTexture9 *getTexture() const override;
+ size_t getTextureLevel() const override;
+ IDirect3DSurface9 *getSurface() const override;
+
+ D3DFORMAT getD3DFormat() const override;
+
+ private:
+ GLsizei mWidth;
+ GLsizei mHeight;
+ GLsizei mDepth;
+ GLenum mInternalFormat;
+ D3DFORMAT mD3DFormat;
+ GLsizei mSamples;
+
+ IDirect3DBaseTexture9 *mTexture;
+ size_t mTextureLevel;
+ IDirect3DSurface9 *mRenderTarget;
+};
+
+class SurfaceRenderTarget9 : public RenderTarget9
+{
+ public:
+ SurfaceRenderTarget9(SwapChain9 *swapChain, bool depth);
+ virtual ~SurfaceRenderTarget9();
+
+ GLsizei getWidth() const override;
+ GLsizei getHeight() const override;
+ GLsizei getDepth() const override;
+ GLenum getInternalFormat() const override;
+ GLsizei getSamples() const override;
+
+ IDirect3DBaseTexture9 *getTexture() const override;
+ size_t getTextureLevel() const override;
+ IDirect3DSurface9 *getSurface() const override;
+
+ D3DFORMAT getD3DFormat() const override;
+
+ private:
+ SwapChain9 *mSwapChain;
+ bool mDepth;
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_RENDERTARGET9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
new file mode 100755
index 000000000..d578d4075
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
@@ -0,0 +1,3032 @@
+//
+// Copyright (c) 2012-2014 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.
+//
+
+// Renderer9.cpp: Implements a back-end specific class for the D3D9 renderer.
+
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+
+#include <sstream>
+#include <EGL/eglext.h>
+
+#include "common/utilities.h"
+#include "libANGLE/angletypes.h"
+#include "libANGLE/Buffer.h"
+#include "libANGLE/Display.h"
+#include "libANGLE/features.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/Framebuffer.h"
+#include "libANGLE/FramebufferAttachment.h"
+#include "libANGLE/Program.h"
+#include "libANGLE/Renderbuffer.h"
+#include "libANGLE/renderer/d3d/d3d9/Blit9.h"
+#include "libANGLE/renderer/d3d/d3d9/Buffer9.h"
+#include "libANGLE/renderer/d3d/d3d9/Context9.h"
+#include "libANGLE/renderer/d3d/d3d9/Fence9.h"
+#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
+#include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h"
+#include "libANGLE/renderer/d3d/d3d9/Image9.h"
+#include "libANGLE/renderer/d3d/d3d9/IndexBuffer9.h"
+#include "libANGLE/renderer/d3d/d3d9/NativeWindow9.h"
+#include "libANGLE/renderer/d3d/d3d9/Query9.h"
+#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
+#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
+#include "libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h"
+#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h"
+#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h"
+#include "libANGLE/renderer/d3d/d3d9/VertexArray9.h"
+#include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h"
+#include "libANGLE/renderer/d3d/CompilerD3D.h"
+#include "libANGLE/renderer/d3d/DeviceD3D.h"
+#include "libANGLE/renderer/d3d/FramebufferD3D.h"
+#include "libANGLE/renderer/d3d/IndexDataManager.h"
+#include "libANGLE/renderer/d3d/ProgramD3D.h"
+#include "libANGLE/renderer/d3d/RenderbufferD3D.h"
+#include "libANGLE/renderer/d3d/ShaderD3D.h"
+#include "libANGLE/renderer/d3d/SurfaceD3D.h"
+#include "libANGLE/renderer/d3d/TextureD3D.h"
+#include "libANGLE/State.h"
+#include "libANGLE/Surface.h"
+#include "libANGLE/Texture.h"
+#include "third_party/trace_event/trace_event.h"
+
+
+
+#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL)
+#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3
+#endif
+
+// Enable ANGLE_SUPPORT_SHADER_MODEL_2 if you wish devices with only shader model 2.
+// Such a device would not be conformant.
+#ifndef ANGLE_SUPPORT_SHADER_MODEL_2
+#define ANGLE_SUPPORT_SHADER_MODEL_2 0
+#endif
+
+namespace rx
+{
+
+enum
+{
+ MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256,
+ MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32,
+ MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224,
+ MAX_VARYING_VECTORS_SM2 = 8,
+ MAX_VARYING_VECTORS_SM3 = 10,
+
+ MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4
+};
+
+Renderer9::Renderer9(egl::Display *display) : RendererD3D(display), mStateManager(this)
+{
+ mD3d9Module = NULL;
+
+ mD3d9 = NULL;
+ mD3d9Ex = NULL;
+ mDevice = NULL;
+ mDeviceEx = NULL;
+ mDeviceWindow = NULL;
+ mBlit = NULL;
+
+ mAdapter = D3DADAPTER_DEFAULT;
+
+ const egl::AttributeMap &attributes = display->getAttributeMap();
+ EGLint requestedDeviceType = static_cast<EGLint>(attributes.get(
+ EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE));
+ switch (requestedDeviceType)
+ {
+ case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE:
+ mDeviceType = D3DDEVTYPE_HAL;
+ break;
+
+ case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE:
+ mDeviceType = D3DDEVTYPE_REF;
+ break;
+
+ case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE:
+ mDeviceType = D3DDEVTYPE_NULLREF;
+ break;
+
+ default:
+ UNREACHABLE();
+ }
+
+ mMaskedClearSavedState = NULL;
+
+ mVertexDataManager = NULL;
+ mIndexDataManager = NULL;
+ mLineLoopIB = NULL;
+ mCountingIB = NULL;
+
+ mMaxNullColorbufferLRU = 0;
+ for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
+ {
+ mNullColorbufferCache[i].lruCount = 0;
+ mNullColorbufferCache[i].width = 0;
+ mNullColorbufferCache[i].height = 0;
+ mNullColorbufferCache[i].buffer = NULL;
+ }
+
+ mAppliedVertexShader = NULL;
+ mAppliedPixelShader = NULL;
+ mAppliedProgramSerial = 0;
+
+ gl::InitializeDebugAnnotations(&mAnnotator);
+
+ mEGLDevice = nullptr;
+}
+
+Renderer9::~Renderer9()
+{
+ if (mDevice)
+ {
+ // If the device is lost, reset it first to prevent leaving the driver in an unstable state
+ if (testDeviceLost())
+ {
+ resetDevice();
+ }
+ }
+
+ release();
+}
+
+void Renderer9::release()
+{
+ RendererD3D::cleanup();
+
+ gl::UninitializeDebugAnnotations();
+
+ mTranslatedAttribCache.clear();
+
+ releaseDeviceResources();
+
+ SafeDelete(mEGLDevice);
+ SafeRelease(mDevice);
+ SafeRelease(mDeviceEx);
+ SafeRelease(mD3d9);
+ SafeRelease(mD3d9Ex);
+
+ mCompiler.release();
+
+ if (mDeviceWindow)
+ {
+ DestroyWindow(mDeviceWindow);
+ mDeviceWindow = NULL;
+ }
+
+ mD3d9Module = NULL;
+}
+
+egl::Error Renderer9::initialize()
+{
+ TRACE_EVENT0("gpu.angle", "GetModuleHandle_d3d9");
+ mD3d9Module = GetModuleHandle(TEXT("d3d9.dll"));
+
+ if (mD3d9Module == NULL)
+ {
+ return egl::Error(EGL_NOT_INITIALIZED, D3D9_INIT_MISSING_DEP, "No D3D9 module found.");
+ }
+
+ typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**);
+ Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast<Direct3DCreate9ExFunc>(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex"));
+
+ // Use Direct3D9Ex if available. Among other things, this version is less
+ // inclined to report a lost context, for example when the user switches
+ // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available.
+ if (ANGLE_D3D9EX == ANGLE_ENABLED && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex)))
+ {
+ TRACE_EVENT0("gpu.angle", "D3d9Ex_QueryInterface");
+ ASSERT(mD3d9Ex);
+ mD3d9Ex->QueryInterface(__uuidof(IDirect3D9), reinterpret_cast<void**>(&mD3d9));
+ ASSERT(mD3d9);
+ }
+ else
+ {
+ TRACE_EVENT0("gpu.angle", "Direct3DCreate9");
+ mD3d9 = Direct3DCreate9(D3D_SDK_VERSION);
+ }
+
+ if (!mD3d9)
+ {
+ return egl::Error(EGL_NOT_INITIALIZED, D3D9_INIT_MISSING_DEP, "Could not create D3D9 device.");
+ }
+
+ if (mDisplay->getNativeDisplayId() != nullptr)
+ {
+ // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to
+ }
+
+ HRESULT result;
+
+ // Give up on getting device caps after about one second.
+ {
+ TRACE_EVENT0("gpu.angle", "GetDeviceCaps");
+ for (int i = 0; i < 10; ++i)
+ {
+ result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps);
+ if (SUCCEEDED(result))
+ {
+ break;
+ }
+ else if (result == D3DERR_NOTAVAILABLE)
+ {
+ Sleep(100); // Give the driver some time to initialize/recover
+ }
+ else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, D3DERR_INVALIDDEVICE, or another error we can't recover from
+ {
+ return egl::Error(EGL_NOT_INITIALIZED,
+ D3D9_INIT_OTHER_ERROR,
+ "Failed to get device caps: Error code 0x%x\n", result);
+ }
+ }
+ }
+
+#if ANGLE_SUPPORT_SHADER_MODEL_2
+ size_t minShaderModel = 2;
+#else
+ size_t minShaderModel = 3;
+#endif
+
+ if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(minShaderModel, 0))
+ {
+ return egl::Error(EGL_NOT_INITIALIZED,
+ D3D9_INIT_UNSUPPORTED_VERSION,
+ "Renderer does not support PS %u.%u.aborting!", minShaderModel, 0);
+ }
+
+ // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported.
+ // This is required by Texture2D::ensureRenderTarget.
+ if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0)
+ {
+ return egl::Error(EGL_NOT_INITIALIZED,
+ D3D9_INIT_UNSUPPORTED_STRETCHRECT,
+ "Renderer does not support StretctRect from textures.");
+ }
+
+ {
+ TRACE_EVENT0("gpu.angle", "GetAdapterIdentifier");
+ mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier);
+ }
+
+ static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
+ static const TCHAR className[] = TEXT("STATIC");
+
+ {
+ TRACE_EVENT0("gpu.angle", "CreateWindowEx");
+ mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
+ }
+
+ D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
+ DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED;
+
+ {
+ TRACE_EVENT0("gpu.angle", "D3d9_CreateDevice");
+ result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
+ }
+ if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST)
+ {
+ return egl::Error(EGL_BAD_ALLOC, D3D9_INIT_OUT_OF_MEMORY,
+ "CreateDevice failed: device lost of out of memory");
+ }
+
+ if (FAILED(result))
+ {
+ TRACE_EVENT0("gpu.angle", "D3d9_CreateDevice2");
+ result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST);
+ return egl::Error(EGL_BAD_ALLOC, D3D9_INIT_OUT_OF_MEMORY,
+ "CreateDevice2 failed: device lost, not available, or of out of memory");
+ }
+ }
+
+ if (mD3d9Ex)
+ {
+ TRACE_EVENT0("gpu.angle", "mDevice_QueryInterface");
+ result = mDevice->QueryInterface(__uuidof(IDirect3DDevice9Ex), (void**)&mDeviceEx);
+ ASSERT(SUCCEEDED(result));
+ }
+
+ {
+ TRACE_EVENT0("gpu.angle", "ShaderCache initialize");
+ mVertexShaderCache.initialize(mDevice);
+ mPixelShaderCache.initialize(mDevice);
+ }
+
+ D3DDISPLAYMODE currentDisplayMode;
+ mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
+
+ // Check vertex texture support
+ // Only Direct3D 10 ready devices support all the necessary vertex texture formats.
+ // We test this using D3D9 by checking support for the R16F format.
+ mVertexTextureSupport = mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0) &&
+ SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format,
+ D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F));
+
+ initializeDevice();
+
+ return egl::Error(EGL_SUCCESS);
+}
+
+// do any one-time device initialization
+// NOTE: this is also needed after a device lost/reset
+// to reset the scene status and ensure the default states are reset.
+void Renderer9::initializeDevice()
+{
+ // Permanent non-default states
+ mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
+ mDevice->SetRenderState(D3DRS_LASTPIXEL, FALSE);
+
+ if (mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0))
+ {
+ mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, (DWORD&)mDeviceCaps.MaxPointSize);
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, 0x3F800000); // 1.0f
+ }
+
+ const gl::Caps &rendererCaps = getNativeCaps();
+
+ mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits);
+ mCurPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits);
+
+ mCurVertexTextures.resize(rendererCaps.maxVertexTextureImageUnits);
+ mCurPixelTextures.resize(rendererCaps.maxTextureImageUnits);
+
+ markAllStateDirty();
+
+ mSceneStarted = false;
+
+ ASSERT(!mBlit);
+ mBlit = new Blit9(this);
+ mBlit->initialize();
+
+ ASSERT(!mVertexDataManager && !mIndexDataManager);
+ mVertexDataManager = new VertexDataManager(this);
+ mIndexDataManager = new IndexDataManager(this, getRendererClass());
+
+ mTranslatedAttribCache.resize(getNativeCaps().maxVertexAttributes);
+
+ mStateManager.initialize();
+}
+
+D3DPRESENT_PARAMETERS Renderer9::getDefaultPresentParameters()
+{
+ D3DPRESENT_PARAMETERS presentParameters = {0};
+
+ // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
+ presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
+ presentParameters.BackBufferCount = 1;
+ presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
+ presentParameters.BackBufferWidth = 1;
+ presentParameters.BackBufferHeight = 1;
+ presentParameters.EnableAutoDepthStencil = FALSE;
+ presentParameters.Flags = 0;
+ presentParameters.hDeviceWindow = mDeviceWindow;
+ presentParameters.MultiSampleQuality = 0;
+ presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
+ presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
+ presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ presentParameters.Windowed = TRUE;
+
+ return presentParameters;
+}
+
+egl::ConfigSet Renderer9::generateConfigs()
+{
+ static const GLenum colorBufferFormats[] =
+ {
+ GL_BGR5_A1_ANGLEX,
+ GL_BGRA8_EXT,
+ GL_RGB565,
+
+ };
+
+ static const GLenum depthStencilBufferFormats[] =
+ {
+ GL_NONE,
+ GL_DEPTH_COMPONENT32_OES,
+ GL_DEPTH24_STENCIL8_OES,
+ GL_DEPTH_COMPONENT24_OES,
+ GL_DEPTH_COMPONENT16,
+ };
+
+ const gl::Caps &rendererCaps = getNativeCaps();
+ const gl::TextureCapsMap &rendererTextureCaps = getNativeTextureCaps();
+
+ D3DDISPLAYMODE currentDisplayMode;
+ mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
+
+ // Determine the min and max swap intervals
+ int minSwapInterval = 4;
+ int maxSwapInterval = 0;
+
+ if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE)
+ {
+ minSwapInterval = std::min(minSwapInterval, 0);
+ maxSwapInterval = std::max(maxSwapInterval, 0);
+ }
+ if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE)
+ {
+ minSwapInterval = std::min(minSwapInterval, 1);
+ maxSwapInterval = std::max(maxSwapInterval, 1);
+ }
+ if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO)
+ {
+ minSwapInterval = std::min(minSwapInterval, 2);
+ maxSwapInterval = std::max(maxSwapInterval, 2);
+ }
+ if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE)
+ {
+ minSwapInterval = std::min(minSwapInterval, 3);
+ maxSwapInterval = std::max(maxSwapInterval, 3);
+ }
+ if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR)
+ {
+ minSwapInterval = std::min(minSwapInterval, 4);
+ maxSwapInterval = std::max(maxSwapInterval, 4);
+ }
+
+ egl::ConfigSet configs;
+ for (size_t formatIndex = 0; formatIndex < ArraySize(colorBufferFormats); formatIndex++)
+ {
+ GLenum colorBufferInternalFormat = colorBufferFormats[formatIndex];
+ const gl::TextureCaps &colorBufferFormatCaps = rendererTextureCaps.get(colorBufferInternalFormat);
+ if (colorBufferFormatCaps.renderable)
+ {
+ for (size_t depthStencilIndex = 0; depthStencilIndex < ArraySize(depthStencilBufferFormats); depthStencilIndex++)
+ {
+ GLenum depthStencilBufferInternalFormat = depthStencilBufferFormats[depthStencilIndex];
+ const gl::TextureCaps &depthStencilBufferFormatCaps = rendererTextureCaps.get(depthStencilBufferInternalFormat);
+ if (depthStencilBufferFormatCaps.renderable || depthStencilBufferInternalFormat == GL_NONE)
+ {
+ const gl::InternalFormat &colorBufferFormatInfo = gl::GetInternalFormatInfo(colorBufferInternalFormat);
+ const gl::InternalFormat &depthStencilBufferFormatInfo = gl::GetInternalFormatInfo(depthStencilBufferInternalFormat);
+ const d3d9::TextureFormat &d3d9ColorBufferFormatInfo = d3d9::GetTextureFormatInfo(colorBufferInternalFormat);
+
+ egl::Config config;
+ config.renderTargetFormat = colorBufferInternalFormat;
+ config.depthStencilFormat = depthStencilBufferInternalFormat;
+ config.bufferSize = colorBufferFormatInfo.pixelBytes * 8;
+ config.redSize = colorBufferFormatInfo.redBits;
+ config.greenSize = colorBufferFormatInfo.greenBits;
+ config.blueSize = colorBufferFormatInfo.blueBits;
+ config.luminanceSize = colorBufferFormatInfo.luminanceBits;
+ config.alphaSize = colorBufferFormatInfo.alphaBits;
+ config.alphaMaskSize = 0;
+ config.bindToTextureRGB = (colorBufferFormatInfo.format == GL_RGB);
+ config.bindToTextureRGBA = (colorBufferFormatInfo.format == GL_RGBA || colorBufferFormatInfo.format == GL_BGRA_EXT);
+ config.colorBufferType = EGL_RGB_BUFFER;
+ // Mark as slow if blits to the back-buffer won't be straight forward
+ config.configCaveat = (currentDisplayMode.Format == d3d9ColorBufferFormatInfo.renderFormat) ? EGL_NONE : EGL_SLOW_CONFIG;
+ config.configID = static_cast<EGLint>(configs.size() + 1);
+ config.conformant = EGL_OPENGL_ES2_BIT;
+ config.depthSize = depthStencilBufferFormatInfo.depthBits;
+ config.level = 0;
+ config.matchNativePixmap = EGL_NONE;
+ config.maxPBufferWidth = rendererCaps.max2DTextureSize;
+ config.maxPBufferHeight = rendererCaps.max2DTextureSize;
+ config.maxPBufferPixels = rendererCaps.max2DTextureSize * rendererCaps.max2DTextureSize;
+ config.maxSwapInterval = maxSwapInterval;
+ config.minSwapInterval = minSwapInterval;
+ config.nativeRenderable = EGL_FALSE;
+ config.nativeVisualID = 0;
+ config.nativeVisualType = EGL_NONE;
+ config.renderableType = EGL_OPENGL_ES2_BIT;
+ config.sampleBuffers = 0; // FIXME: enumerate multi-sampling
+ config.samples = 0;
+ config.stencilSize = depthStencilBufferFormatInfo.stencilBits;
+ config.surfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
+ config.transparentType = EGL_NONE;
+ config.transparentRedValue = 0;
+ config.transparentGreenValue = 0;
+ config.transparentBlueValue = 0;
+
+ configs.add(config);
+ }
+ }
+ }
+ }
+
+ ASSERT(configs.size() > 0);
+ return configs;
+}
+
+void Renderer9::generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const
+{
+ outExtensions->createContextRobustness = true;
+
+ if (getShareHandleSupport())
+ {
+ outExtensions->d3dShareHandleClientBuffer = true;
+ outExtensions->surfaceD3DTexture2DShareHandle = true;
+ }
+ outExtensions->d3dTextureClientBuffer = true;
+
+ outExtensions->querySurfacePointer = true;
+ outExtensions->windowFixedSize = true;
+ outExtensions->postSubBuffer = true;
+ outExtensions->deviceQuery = true;
+
+ outExtensions->image = true;
+ outExtensions->imageBase = true;
+ outExtensions->glTexture2DImage = true;
+ outExtensions->glRenderbufferImage = true;
+
+ outExtensions->flexibleSurfaceCompatibility = true;
+}
+
+void Renderer9::startScene()
+{
+ if (!mSceneStarted)
+ {
+ long result = mDevice->BeginScene();
+ if (SUCCEEDED(result)) {
+ // This is defensive checking against the device being
+ // lost at unexpected times.
+ mSceneStarted = true;
+ }
+ }
+}
+
+void Renderer9::endScene()
+{
+ if (mSceneStarted)
+ {
+ // EndScene can fail if the device was lost, for example due
+ // to a TDR during a draw call.
+ mDevice->EndScene();
+ mSceneStarted = false;
+ }
+}
+
+gl::Error Renderer9::flush()
+{
+ IDirect3DQuery9* query = NULL;
+ gl::Error error = allocateEventQuery(&query);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ HRESULT result = query->Issue(D3DISSUE_END);
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to issue event query, result: 0x%X.", result);
+ }
+
+ // Grab the query data once
+ result = query->GetData(NULL, 0, D3DGETDATA_FLUSH);
+ freeEventQuery(query);
+ if (FAILED(result))
+ {
+ if (d3d9::isDeviceLostError(result))
+ {
+ notifyDeviceLost();
+ }
+
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Renderer9::finish()
+{
+ IDirect3DQuery9* query = NULL;
+ gl::Error error = allocateEventQuery(&query);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ HRESULT result = query->Issue(D3DISSUE_END);
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to issue event query, result: 0x%X.", result);
+ }
+
+ // Grab the query data once
+ result = query->GetData(NULL, 0, D3DGETDATA_FLUSH);
+ if (FAILED(result))
+ {
+ if (d3d9::isDeviceLostError(result))
+ {
+ notifyDeviceLost();
+ }
+
+ freeEventQuery(query);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result);
+ }
+
+ // Loop until the query completes
+ while (result == S_FALSE)
+ {
+ // Keep polling, but allow other threads to do something useful first
+ ScheduleYield();
+
+ result = query->GetData(NULL, 0, D3DGETDATA_FLUSH);
+
+ // explicitly check for device loss
+ // some drivers seem to return S_FALSE even if the device is lost
+ // instead of D3DERR_DEVICELOST like they should
+ if (result == S_FALSE && testDeviceLost())
+ {
+ result = D3DERR_DEVICELOST;
+ }
+
+ if (FAILED(result))
+ {
+ if (d3d9::isDeviceLostError(result))
+ {
+ notifyDeviceLost();
+ }
+
+ freeEventQuery(query);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result);
+ }
+
+ }
+
+ freeEventQuery(query);
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+bool Renderer9::isValidNativeWindow(EGLNativeWindowType window) const
+{
+ return NativeWindow9::IsValidNativeWindow(window);
+}
+
+NativeWindowD3D *Renderer9::createNativeWindow(EGLNativeWindowType window,
+ const egl::Config *,
+ const egl::AttributeMap &) const
+{
+ return new NativeWindow9(window);
+}
+
+SwapChainD3D *Renderer9::createSwapChain(NativeWindowD3D *nativeWindow,
+ HANDLE shareHandle,
+ IUnknown *d3dTexture,
+ GLenum backBufferFormat,
+ GLenum depthBufferFormat,
+ EGLint orientation)
+{
+ return new SwapChain9(this, GetAs<NativeWindow9>(nativeWindow), shareHandle, d3dTexture,
+ backBufferFormat, depthBufferFormat, orientation);
+}
+
+egl::Error Renderer9::getD3DTextureInfo(IUnknown *d3dTexture,
+ EGLint *width,
+ EGLint *height,
+ GLenum *fboFormat) const
+{
+ IDirect3DTexture9 *texture = nullptr;
+ if (FAILED(d3dTexture->QueryInterface(&texture)))
+ {
+ return egl::Error(EGL_BAD_PARAMETER, "client buffer is not a IDirect3DTexture9");
+ }
+
+ IDirect3DDevice9 *textureDevice = nullptr;
+ texture->GetDevice(&textureDevice);
+ if (textureDevice != mDevice)
+ {
+ SafeRelease(texture);
+ return egl::Error(EGL_BAD_PARAMETER, "Texture's device does not match.");
+ }
+ SafeRelease(textureDevice);
+
+ D3DSURFACE_DESC desc;
+ texture->GetLevelDesc(0, &desc);
+ SafeRelease(texture);
+
+ if (width)
+ {
+ *width = static_cast<EGLint>(desc.Width);
+ }
+ if (height)
+ {
+ *height = static_cast<EGLint>(desc.Height);
+ }
+
+ // From table egl.restrictions in EGL_ANGLE_d3d_texture_client_buffer.
+ switch (desc.Format)
+ {
+ case D3DFMT_R8G8B8:
+ case D3DFMT_A8R8G8B8:
+ case D3DFMT_A16B16G16R16F:
+ case D3DFMT_A32B32G32R32F:
+ break;
+
+ default:
+ return egl::Error(EGL_BAD_PARAMETER, "Unknown client buffer texture format: %u.",
+ desc.Format);
+ }
+
+ if (fboFormat)
+ {
+ const auto &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
+ ASSERT(d3dFormatInfo.info().id != angle::Format::ID::NONE);
+ *fboFormat = d3dFormatInfo.info().fboImplementationInternalFormat;
+ }
+
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error Renderer9::validateShareHandle(const egl::Config *config,
+ HANDLE shareHandle,
+ const egl::AttributeMap &attribs) const
+{
+ if (shareHandle == nullptr)
+ {
+ return egl::Error(EGL_BAD_PARAMETER, "NULL share handle.");
+ }
+
+ EGLint width = attribs.getAsInt(EGL_WIDTH, 0);
+ EGLint height = attribs.getAsInt(EGL_HEIGHT, 0);
+ ASSERT(width != 0 && height != 0);
+
+ const d3d9::TextureFormat &backBufferd3dFormatInfo =
+ d3d9::GetTextureFormatInfo(config->renderTargetFormat);
+
+ IDirect3DTexture9 *texture = nullptr;
+ HRESULT result = mDevice->CreateTexture(width, height, 1, D3DUSAGE_RENDERTARGET,
+ backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT,
+ &texture, &shareHandle);
+ if (FAILED(result))
+ {
+ return egl::Error(EGL_BAD_PARAMETER, "Failed to open share handle, result: 0x%X.", result);
+ }
+
+ DWORD levelCount = texture->GetLevelCount();
+
+ D3DSURFACE_DESC desc;
+ texture->GetLevelDesc(0, &desc);
+ SafeRelease(texture);
+
+ if (levelCount != 1 || desc.Width != static_cast<UINT>(width) ||
+ desc.Height != static_cast<UINT>(height) ||
+ desc.Format != backBufferd3dFormatInfo.texFormat)
+ {
+ return egl::Error(EGL_BAD_PARAMETER, "Invalid texture parameters in share handle texture.");
+ }
+
+ return egl::Error(EGL_SUCCESS);
+}
+
+ContextImpl *Renderer9::createContext(const gl::ContextState &state)
+{
+ return new Context9(state, this);
+}
+
+void *Renderer9::getD3DDevice()
+{
+ return reinterpret_cast<void*>(mDevice);
+}
+
+gl::Error Renderer9::allocateEventQuery(IDirect3DQuery9 **outQuery)
+{
+ if (mEventQueryPool.empty())
+ {
+ HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, outQuery);
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate event query, result: 0x%X.", result);
+ }
+ }
+ else
+ {
+ *outQuery = mEventQueryPool.back();
+ mEventQueryPool.pop_back();
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+void Renderer9::freeEventQuery(IDirect3DQuery9* query)
+{
+ if (mEventQueryPool.size() > 1000)
+ {
+ SafeRelease(query);
+ }
+ else
+ {
+ mEventQueryPool.push_back(query);
+ }
+}
+
+gl::Error Renderer9::createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader)
+{
+ return mVertexShaderCache.create(function, length, outShader);
+}
+
+gl::Error Renderer9::createPixelShader(const DWORD *function, size_t length, IDirect3DPixelShader9 **outShader)
+{
+ return mPixelShaderCache.create(function, length, outShader);
+}
+
+HRESULT Renderer9::createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer)
+{
+ D3DPOOL Pool = getBufferPool(Usage);
+ return mDevice->CreateVertexBuffer(Length, Usage, 0, Pool, ppVertexBuffer, NULL);
+}
+
+VertexBuffer *Renderer9::createVertexBuffer()
+{
+ return new VertexBuffer9(this);
+}
+
+HRESULT Renderer9::createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer)
+{
+ D3DPOOL Pool = getBufferPool(Usage);
+ return mDevice->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, NULL);
+}
+
+IndexBuffer *Renderer9::createIndexBuffer()
+{
+ return new IndexBuffer9(this);
+}
+
+StreamProducerImpl *Renderer9::createStreamProducerD3DTextureNV12(
+ egl::Stream::ConsumerType consumerType,
+ const egl::AttributeMap &attribs)
+{
+ // Streams are not supported under D3D9
+ UNREACHABLE();
+ return nullptr;
+}
+
+bool Renderer9::supportsFastCopyBufferToTexture(GLenum internalFormat) const
+{
+ // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3.
+ return false;
+}
+
+gl::Error Renderer9::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget,
+ GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea)
+{
+ // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3.
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &samplerState)
+{
+ CurSamplerState &appliedSampler = (type == gl::SAMPLER_PIXEL) ? mCurPixelSamplerStates[index]
+ : mCurVertexSamplerStates[index];
+
+ // Make sure to add the level offset for our tiny compressed texture workaround
+ TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture);
+
+ TextureStorage *storage = nullptr;
+ gl::Error error = textureD3D->getNativeTexture(&storage);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ // Storage should exist, texture should be complete
+ ASSERT(storage);
+
+ DWORD baseLevel = texture->getBaseLevel() + storage->getTopLevel();
+
+ if (appliedSampler.forceSet || appliedSampler.baseLevel != baseLevel ||
+ memcmp(&samplerState, &appliedSampler, sizeof(gl::SamplerState)) != 0)
+ {
+ int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0;
+ int d3dSampler = index + d3dSamplerOffset;
+
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, gl_d3d9::ConvertTextureWrap(samplerState.wrapS));
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, gl_d3d9::ConvertTextureWrap(samplerState.wrapT));
+
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, gl_d3d9::ConvertMagFilter(samplerState.magFilter, samplerState.maxAnisotropy));
+
+ D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter;
+ float lodBias;
+ gl_d3d9::ConvertMinFilter(samplerState.minFilter, &d3dMinFilter, &d3dMipFilter, &lodBias,
+ samplerState.maxAnisotropy, baseLevel);
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter);
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter);
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, baseLevel);
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPMAPLODBIAS, static_cast<DWORD>(lodBias));
+ if (getNativeExtensions().textureFilterAnisotropic)
+ {
+ DWORD maxAnisotropy =
+ std::min(mDeviceCaps.MaxAnisotropy, static_cast<DWORD>(samplerState.maxAnisotropy));
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, maxAnisotropy);
+ }
+ }
+
+ appliedSampler.forceSet = false;
+ appliedSampler.samplerState = samplerState;
+ appliedSampler.baseLevel = baseLevel;
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *texture)
+{
+ int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0;
+ int d3dSampler = index + d3dSamplerOffset;
+ IDirect3DBaseTexture9 *d3dTexture = NULL;
+ bool forceSetTexture = false;
+
+ std::vector<uintptr_t> &appliedTextures = (type == gl::SAMPLER_PIXEL) ? mCurPixelTextures : mCurVertexTextures;
+
+ if (texture)
+ {
+ TextureD3D *textureImpl = GetImplAs<TextureD3D>(texture);
+
+ TextureStorage *texStorage = nullptr;
+ gl::Error error = textureImpl->getNativeTexture(&texStorage);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ // Texture should be complete and have a storage
+ ASSERT(texStorage);
+
+ TextureStorage9 *storage9 = GetAs<TextureStorage9>(texStorage);
+ error = storage9->getBaseTexture(&d3dTexture);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ // If we get NULL back from getBaseTexture here, something went wrong
+ // in the texture class and we're unexpectedly missing the d3d texture
+ ASSERT(d3dTexture != NULL);
+
+ forceSetTexture = textureImpl->hasDirtyImages();
+ textureImpl->resetDirty();
+ }
+
+ if (forceSetTexture || appliedTextures[index] != reinterpret_cast<uintptr_t>(d3dTexture))
+ {
+ mDevice->SetTexture(d3dSampler, d3dTexture);
+ }
+
+ appliedTextures[index] = reinterpret_cast<uintptr_t>(d3dTexture);
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Renderer9::setUniformBuffers(const gl::ContextState & /*data*/,
+ const std::vector<GLint> & /*vertexUniformBuffers*/,
+ const std::vector<GLint> & /*fragmentUniformBuffers*/)
+{
+ // No effect in ES2/D3D9
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Renderer9::updateState(Context9 *context, GLenum drawMode)
+{
+ const auto &data = context->getContextState();
+ const auto &glState = data.getState();
+
+ // Applies the render target surface, depth stencil surface, viewport rectangle and
+ // scissor rectangle to the renderer
+ gl::Framebuffer *framebuffer = glState.getDrawFramebuffer();
+ ASSERT(framebuffer && !framebuffer->hasAnyDirtyBit() && framebuffer->complete(data));
+
+ ANGLE_TRY(applyRenderTarget(context, framebuffer));
+
+ // Setting viewport state
+ setViewport(glState.getViewport(), glState.getNearPlane(), glState.getFarPlane(), drawMode,
+ glState.getRasterizerState().frontFace, false);
+
+ // Setting scissors state
+ setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled());
+
+ // Setting blend, depth stencil, and rasterizer states
+ // Since framebuffer->getSamples will return the original samples which may be different with
+ // the sample counts that we set in render target view, here we use renderTarget->getSamples to
+ // get the actual samples.
+ GLsizei samples = 0;
+ auto firstColorAttachment = framebuffer->getFirstColorbuffer();
+ if (firstColorAttachment)
+ {
+ ASSERT(firstColorAttachment->isAttached());
+ RenderTarget9 *renderTarget = nullptr;
+ ANGLE_TRY(firstColorAttachment->getRenderTarget(&renderTarget));
+ samples = renderTarget->getSamples();
+ }
+ gl::RasterizerState rasterizer = glState.getRasterizerState();
+ rasterizer.pointDrawMode = (drawMode == GL_POINTS);
+ rasterizer.multiSample = (samples != 0);
+
+ unsigned int mask = GetBlendSampleMask(data, samples);
+ ANGLE_TRY(setBlendDepthRasterStates(data, mask));
+
+ mStateManager.resetDirtyBits();
+
+ return gl::NoError();
+}
+
+void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled)
+{
+ mStateManager.setScissorState(scissor, enabled);
+}
+
+gl::Error Renderer9::setBlendDepthRasterStates(const gl::ContextState &glData, GLenum drawMode)
+{
+ const auto &glState = glData.getState();
+ auto drawFramebuffer = glState.getDrawFramebuffer();
+ ASSERT(!drawFramebuffer->hasAnyDirtyBit());
+ // Since framebuffer->getSamples will return the original samples which may be different with
+ // the sample counts that we set in render target view, here we use renderTarget->getSamples to
+ // get the actual samples.
+ GLsizei samples = 0;
+ auto firstColorAttachment = drawFramebuffer->getFirstColorbuffer();
+ if (firstColorAttachment)
+ {
+ ASSERT(firstColorAttachment->isAttached());
+ RenderTarget9 *renderTarget = nullptr;
+ ANGLE_TRY(firstColorAttachment->getRenderTarget(&renderTarget));
+ samples = renderTarget->getSamples();
+ }
+ gl::RasterizerState rasterizer = glState.getRasterizerState();
+ rasterizer.pointDrawMode = (drawMode == GL_POINTS);
+ rasterizer.multiSample = (samples != 0);
+
+ unsigned int mask = GetBlendSampleMask(glData, samples);
+ return mStateManager.setBlendDepthRasterStates(glState, mask);
+}
+
+void Renderer9::setViewport(const gl::Rectangle &viewport,
+ float zNear,
+ float zFar,
+ GLenum drawMode,
+ GLenum frontFace,
+ bool ignoreViewport)
+{
+ mStateManager.setViewportState(viewport, zNear, zFar, drawMode, frontFace, ignoreViewport);
+}
+
+bool Renderer9::applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize)
+{
+ switch (mode)
+ {
+ case GL_POINTS:
+ mPrimitiveType = D3DPT_POINTLIST;
+ mPrimitiveCount = count;
+ break;
+ case GL_LINES:
+ mPrimitiveType = D3DPT_LINELIST;
+ mPrimitiveCount = count / 2;
+ break;
+ case GL_LINE_LOOP:
+ mPrimitiveType = D3DPT_LINESTRIP;
+ mPrimitiveCount = count - 1; // D3D doesn't support line loops, so we draw the last line separately
+ break;
+ case GL_LINE_STRIP:
+ mPrimitiveType = D3DPT_LINESTRIP;
+ mPrimitiveCount = count - 1;
+ break;
+ case GL_TRIANGLES:
+ mPrimitiveType = D3DPT_TRIANGLELIST;
+ mPrimitiveCount = count / 3;
+ break;
+ case GL_TRIANGLE_STRIP:
+ mPrimitiveType = D3DPT_TRIANGLESTRIP;
+ mPrimitiveCount = count - 2;
+ break;
+ case GL_TRIANGLE_FAN:
+ mPrimitiveType = D3DPT_TRIANGLEFAN;
+ mPrimitiveCount = count - 2;
+ break;
+ default:
+ UNREACHABLE();
+ return false;
+ }
+
+ return mPrimitiveCount > 0;
+}
+
+gl::Error Renderer9::getNullColorbuffer(GLImplFactory *implFactory,
+ const gl::FramebufferAttachment *depthbuffer,
+ const gl::FramebufferAttachment **outColorBuffer)
+{
+ ASSERT(depthbuffer);
+
+ const gl::Extents &size = depthbuffer->getSize();
+
+ // search cached nullcolorbuffers
+ for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
+ {
+ if (mNullColorbufferCache[i].buffer != NULL &&
+ mNullColorbufferCache[i].width == size.width &&
+ mNullColorbufferCache[i].height == size.height)
+ {
+ mNullColorbufferCache[i].lruCount = ++mMaxNullColorbufferLRU;
+ *outColorBuffer = mNullColorbufferCache[i].buffer;
+ return gl::Error(GL_NO_ERROR);
+ }
+ }
+
+ gl::Renderbuffer *nullRenderbuffer = new gl::Renderbuffer(implFactory->createRenderbuffer(), 0);
+ gl::Error error = nullRenderbuffer->setStorage(GL_NONE, size.width, size.height);
+ if (error.isError())
+ {
+ SafeDelete(nullRenderbuffer);
+ return error;
+ }
+
+ gl::FramebufferAttachment *nullbuffer = new gl::FramebufferAttachment(GL_RENDERBUFFER, GL_NONE, gl::ImageIndex::MakeInvalid(), nullRenderbuffer);
+
+ // add nullbuffer to the cache
+ NullColorbufferCacheEntry *oldest = &mNullColorbufferCache[0];
+ for (int i = 1; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
+ {
+ if (mNullColorbufferCache[i].lruCount < oldest->lruCount)
+ {
+ oldest = &mNullColorbufferCache[i];
+ }
+ }
+
+ delete oldest->buffer;
+ oldest->buffer = nullbuffer;
+ oldest->lruCount = ++mMaxNullColorbufferLRU;
+ oldest->width = size.width;
+ oldest->height = size.height;
+
+ *outColorBuffer = nullbuffer;
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Renderer9::applyRenderTarget(GLImplFactory *implFactory,
+ const gl::FramebufferAttachment *colorAttachment,
+ const gl::FramebufferAttachment *depthStencilAttachment)
+{
+ const gl::FramebufferAttachment *renderAttachment = colorAttachment;
+ gl::Error error(GL_NO_ERROR);
+
+ // if there is no color attachment we must synthesize a NULL colorattachment
+ // to keep the D3D runtime happy. This should only be possible if depth texturing.
+ if (renderAttachment == nullptr)
+ {
+ error = getNullColorbuffer(implFactory, depthStencilAttachment, &renderAttachment);
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+ ASSERT(renderAttachment != nullptr);
+
+ size_t renderTargetWidth = 0;
+ size_t renderTargetHeight = 0;
+ D3DFORMAT renderTargetFormat = D3DFMT_UNKNOWN;
+
+ RenderTarget9 *renderTarget = nullptr;
+ error = renderAttachment->getRenderTarget(&renderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+ ASSERT(renderTarget);
+
+ bool renderTargetChanged = false;
+ unsigned int renderTargetSerial = renderTarget->getSerial();
+ if (renderTargetSerial != mAppliedRenderTargetSerial)
+ {
+ // Apply the render target on the device
+ IDirect3DSurface9 *renderTargetSurface = renderTarget->getSurface();
+ ASSERT(renderTargetSurface);
+
+ mDevice->SetRenderTarget(0, renderTargetSurface);
+ SafeRelease(renderTargetSurface);
+
+ renderTargetWidth = renderTarget->getWidth();
+ renderTargetHeight = renderTarget->getHeight();
+ renderTargetFormat = renderTarget->getD3DFormat();
+
+ mAppliedRenderTargetSerial = renderTargetSerial;
+ renderTargetChanged = true;
+ }
+
+ RenderTarget9 *depthStencilRenderTarget = nullptr;
+ unsigned int depthStencilSerial = 0;
+
+ if (depthStencilAttachment != nullptr)
+ {
+ error = depthStencilAttachment->getRenderTarget(&depthStencilRenderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+ ASSERT(depthStencilRenderTarget);
+
+ depthStencilSerial = depthStencilRenderTarget->getSerial();
+ }
+
+ if (depthStencilSerial != mAppliedDepthStencilSerial || !mDepthStencilInitialized)
+ {
+ unsigned int depthSize = 0;
+ unsigned int stencilSize = 0;
+
+ // Apply the depth stencil on the device
+ if (depthStencilRenderTarget)
+ {
+ IDirect3DSurface9 *depthStencilSurface = depthStencilRenderTarget->getSurface();
+ ASSERT(depthStencilSurface);
+
+ mDevice->SetDepthStencilSurface(depthStencilSurface);
+ SafeRelease(depthStencilSurface);
+
+ depthSize = depthStencilAttachment->getDepthSize();
+ stencilSize = depthStencilAttachment->getStencilSize();
+ }
+ else
+ {
+ mDevice->SetDepthStencilSurface(NULL);
+ }
+
+ mStateManager.updateDepthSizeIfChanged(mDepthStencilInitialized, depthSize);
+ mStateManager.updateStencilSizeIfChanged(mDepthStencilInitialized, stencilSize);
+
+ mAppliedDepthStencilSerial = depthStencilSerial;
+ mDepthStencilInitialized = true;
+ }
+
+ if (renderTargetChanged || !mRenderTargetDescInitialized)
+ {
+ mStateManager.forceSetBlendState();
+ mStateManager.forceSetScissorState();
+ mStateManager.setRenderTargetBounds(renderTargetWidth, renderTargetHeight);
+ mRenderTargetDescInitialized = true;
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Renderer9::applyRenderTarget(GLImplFactory *implFactory,
+ const gl::Framebuffer *framebuffer)
+{
+ return applyRenderTarget(implFactory, framebuffer->getColorbuffer(0),
+ framebuffer->getDepthOrStencilbuffer());
+}
+
+gl::Error Renderer9::applyVertexBuffer(const gl::State &state,
+ GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei instances,
+ TranslatedIndexData * /*indexInfo*/)
+{
+ gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, &mTranslatedAttribCache, instances);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ return mVertexDeclarationCache.applyDeclaration(
+ mDevice, mTranslatedAttribCache, state.getProgram(), first, instances, &mRepeatDraw);
+}
+
+// Applies the indices and element array bindings to the Direct3D 9 device
+gl::Error Renderer9::applyIndexBuffer(const gl::ContextState &data,
+ const GLvoid *indices,
+ GLsizei count,
+ GLenum mode,
+ GLenum type,
+ TranslatedIndexData *indexInfo)
+{
+ gl::VertexArray *vao = data.getState().getVertexArray();
+ gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
+ gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices,
+ indexInfo, false);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ // Directly binding the storage buffer is not supported for d3d9
+ ASSERT(indexInfo->storage == NULL);
+
+ if (indexInfo->serial != mAppliedIBSerial)
+ {
+ IndexBuffer9* indexBuffer = GetAs<IndexBuffer9>(indexInfo->indexBuffer);
+
+ mDevice->SetIndices(indexBuffer->getBuffer());
+ mAppliedIBSerial = indexInfo->serial;
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Renderer9::applyTransformFeedbackBuffers(const gl::State &state)
+{
+ ASSERT(!state.isTransformFeedbackActiveUnpaused());
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Renderer9::drawArraysImpl(const gl::ContextState &data,
+ GLenum mode,
+ GLint startVertex,
+ GLsizei count,
+ GLsizei instances)
+{
+ ASSERT(!data.getState().isTransformFeedbackActiveUnpaused());
+
+ startScene();
+
+ if (mode == GL_LINE_LOOP)
+ {
+ return drawLineLoop(count, GL_NONE, NULL, 0, NULL);
+ }
+ else if (instances > 0)
+ {
+ StaticIndexBufferInterface *countingIB = NULL;
+ gl::Error error = getCountingIB(count, &countingIB);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ if (mAppliedIBSerial != countingIB->getSerial())
+ {
+ IndexBuffer9 *indexBuffer = GetAs<IndexBuffer9>(countingIB->getIndexBuffer());
+
+ mDevice->SetIndices(indexBuffer->getBuffer());
+ mAppliedIBSerial = countingIB->getSerial();
+ }
+
+ for (int i = 0; i < mRepeatDraw; i++)
+ {
+ mDevice->DrawIndexedPrimitive(mPrimitiveType, 0, 0, count, 0, mPrimitiveCount);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+ }
+ else // Regular case
+ {
+ mDevice->DrawPrimitive(mPrimitiveType, 0, mPrimitiveCount);
+ return gl::Error(GL_NO_ERROR);
+ }
+}
+
+gl::Error Renderer9::drawElementsImpl(const gl::ContextState &data,
+ const TranslatedIndexData &indexInfo,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei /*instances*/)
+{
+ startScene();
+
+ int minIndex = static_cast<int>(indexInfo.indexRange.start);
+
+ gl::VertexArray *vao = data.getState().getVertexArray();
+ gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
+
+ if (mode == GL_POINTS)
+ {
+ return drawIndexedPoints(count, type, indices, minIndex, elementArrayBuffer);
+ }
+ else if (mode == GL_LINE_LOOP)
+ {
+ return drawLineLoop(count, type, indices, minIndex, elementArrayBuffer);
+ }
+ else
+ {
+ size_t vertexCount = indexInfo.indexRange.vertexCount();
+ for (int i = 0; i < mRepeatDraw; i++)
+ {
+ mDevice->DrawIndexedPrimitive(mPrimitiveType, -minIndex, minIndex,
+ static_cast<UINT>(vertexCount), indexInfo.startIndex,
+ mPrimitiveCount);
+ }
+ return gl::Error(GL_NO_ERROR);
+ }
+}
+
+gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer)
+{
+ // Get the raw indices for an indexed draw
+ if (type != GL_NONE && elementArrayBuffer)
+ {
+ BufferD3D *storage = GetImplAs<BufferD3D>(elementArrayBuffer);
+ intptr_t offset = reinterpret_cast<intptr_t>(indices);
+ const uint8_t *bufferData = NULL;
+ gl::Error error = storage->getData(&bufferData);
+ if (error.isError())
+ {
+ return error;
+ }
+ indices = bufferData + offset;
+ }
+
+ unsigned int startIndex = 0;
+
+ if (getNativeExtensions().elementIndexUint)
+ {
+ if (!mLineLoopIB)
+ {
+ mLineLoopIB = new StreamingIndexBufferInterface(this);
+ gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT);
+ if (error.isError())
+ {
+ SafeDelete(mLineLoopIB);
+ return error;
+ }
+ }
+
+ // Checked by Renderer9::applyPrimitiveType
+ ASSERT(count >= 0);
+
+ if (static_cast<unsigned int>(count) + 1 > (std::numeric_limits<unsigned int>::max() / sizeof(unsigned int)))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required.");
+ }
+
+ const unsigned int spaceNeeded = (static_cast<unsigned int>(count)+1) * sizeof(unsigned int);
+ gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ void* mappedMemory = NULL;
+ unsigned int offset = 0;
+ error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ startIndex = static_cast<unsigned int>(offset) / 4;
+ unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
+
+ switch (type)
+ {
+ case GL_NONE: // Non-indexed draw
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = i;
+ }
+ data[count] = 0;
+ break;
+ case GL_UNSIGNED_BYTE:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLubyte*>(indices)[i];
+ }
+ data[count] = static_cast<const GLubyte*>(indices)[0];
+ break;
+ case GL_UNSIGNED_SHORT:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLushort*>(indices)[i];
+ }
+ data[count] = static_cast<const GLushort*>(indices)[0];
+ break;
+ case GL_UNSIGNED_INT:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLuint*>(indices)[i];
+ }
+ data[count] = static_cast<const GLuint*>(indices)[0];
+ break;
+ default: UNREACHABLE();
+ }
+
+ error = mLineLoopIB->unmapBuffer();
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+ else
+ {
+ if (!mLineLoopIB)
+ {
+ mLineLoopIB = new StreamingIndexBufferInterface(this);
+ gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT);
+ if (error.isError())
+ {
+ SafeDelete(mLineLoopIB);
+ return error;
+ }
+ }
+
+ // Checked by Renderer9::applyPrimitiveType
+ ASSERT(count >= 0);
+
+ if (static_cast<unsigned int>(count) + 1 > (std::numeric_limits<unsigned short>::max() / sizeof(unsigned short)))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 16-bit looping index buffer for GL_LINE_LOOP, too many indices required.");
+ }
+
+ const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * sizeof(unsigned short);
+ gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ void* mappedMemory = NULL;
+ unsigned int offset;
+ error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ startIndex = static_cast<unsigned int>(offset) / 2;
+ unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
+
+ switch (type)
+ {
+ case GL_NONE: // Non-indexed draw
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<unsigned short>(i);
+ }
+ data[count] = 0;
+ break;
+ case GL_UNSIGNED_BYTE:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLubyte*>(indices)[i];
+ }
+ data[count] = static_cast<const GLubyte*>(indices)[0];
+ break;
+ case GL_UNSIGNED_SHORT:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLushort*>(indices)[i];
+ }
+ data[count] = static_cast<const GLushort*>(indices)[0];
+ break;
+ case GL_UNSIGNED_INT:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<unsigned short>(static_cast<const GLuint*>(indices)[i]);
+ }
+ data[count] = static_cast<unsigned short>(static_cast<const GLuint*>(indices)[0]);
+ break;
+ default: UNREACHABLE();
+ }
+
+ error = mLineLoopIB->unmapBuffer();
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+
+ if (mAppliedIBSerial != mLineLoopIB->getSerial())
+ {
+ IndexBuffer9 *indexBuffer = GetAs<IndexBuffer9>(mLineLoopIB->getIndexBuffer());
+
+ mDevice->SetIndices(indexBuffer->getBuffer());
+ mAppliedIBSerial = mLineLoopIB->getSerial();
+ }
+
+ mDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, -minIndex, minIndex, count, startIndex, count);
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+template <typename T>
+static gl::Error drawPoints(IDirect3DDevice9* device, GLsizei count, const GLvoid *indices, int minIndex)
+{
+ for (int i = 0; i < count; i++)
+ {
+ unsigned int indexValue = static_cast<unsigned int>(static_cast<const T*>(indices)[i]) - minIndex;
+ device->DrawPrimitive(D3DPT_POINTLIST, indexValue, 1);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer)
+{
+ // Drawing index point lists is unsupported in d3d9, fall back to a regular DrawPrimitive call
+ // for each individual point. This call is not expected to happen often.
+
+ if (elementArrayBuffer)
+ {
+ BufferD3D *storage = GetImplAs<BufferD3D>(elementArrayBuffer);
+ intptr_t offset = reinterpret_cast<intptr_t>(indices);
+
+ const uint8_t *bufferData = NULL;
+ gl::Error error = storage->getData(&bufferData);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ indices = bufferData + offset;
+ }
+
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE: return drawPoints<GLubyte>(mDevice, count, indices, minIndex);
+ case GL_UNSIGNED_SHORT: return drawPoints<GLushort>(mDevice, count, indices, minIndex);
+ case GL_UNSIGNED_INT: return drawPoints<GLuint>(mDevice, count, indices, minIndex);
+ default: UNREACHABLE(); return gl::Error(GL_INVALID_OPERATION);
+ }
+}
+
+gl::Error Renderer9::getCountingIB(size_t count, StaticIndexBufferInterface **outIB)
+{
+ // Update the counting index buffer if it is not large enough or has not been created yet.
+ if (count <= 65536) // 16-bit indices
+ {
+ const unsigned int spaceNeeded = static_cast<unsigned int>(count) * sizeof(unsigned short);
+
+ if (!mCountingIB || mCountingIB->getBufferSize() < spaceNeeded)
+ {
+ SafeDelete(mCountingIB);
+ mCountingIB = new StaticIndexBufferInterface(this);
+ mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
+
+ void *mappedMemory = NULL;
+ gl::Error error = mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, NULL);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
+ for (size_t i = 0; i < count; i++)
+ {
+ data[i] = static_cast<unsigned short>(i);
+ }
+
+ error = mCountingIB->unmapBuffer();
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+ }
+ else if (getNativeExtensions().elementIndexUint)
+ {
+ const unsigned int spaceNeeded = static_cast<unsigned int>(count) * sizeof(unsigned int);
+
+ if (!mCountingIB || mCountingIB->getBufferSize() < spaceNeeded)
+ {
+ SafeDelete(mCountingIB);
+ mCountingIB = new StaticIndexBufferInterface(this);
+ mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
+
+ void *mappedMemory = NULL;
+ gl::Error error = mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, NULL);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
+ for (unsigned int i = 0; i < count; i++)
+ {
+ data[i] = i;
+ }
+
+ error = mCountingIB->unmapBuffer();
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+ }
+ else
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Could not create a counting index buffer for glDrawArraysInstanced.");
+ }
+
+ *outIB = mCountingIB;
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Renderer9::applyShaders(const gl::ContextState &data, GLenum drawMode)
+{
+ ProgramD3D *programD3D = GetImplAs<ProgramD3D>(data.getState().getProgram());
+ programD3D->updateCachedInputLayout(data.getState());
+
+ const auto &inputLayout = programD3D->getCachedInputLayout();
+
+ ShaderExecutableD3D *vertexExe = NULL;
+ ANGLE_TRY(programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe, nullptr));
+
+ const gl::Framebuffer *drawFramebuffer = data.getState().getDrawFramebuffer();
+ ShaderExecutableD3D *pixelExe = NULL;
+ ANGLE_TRY(programD3D->getPixelExecutableForFramebuffer(drawFramebuffer, &pixelExe));
+
+ IDirect3DVertexShader9 *vertexShader = (vertexExe ? GetAs<ShaderExecutable9>(vertexExe)->getVertexShader() : nullptr);
+ IDirect3DPixelShader9 *pixelShader = (pixelExe ? GetAs<ShaderExecutable9>(pixelExe)->getPixelShader() : nullptr);
+
+ if (vertexShader != mAppliedVertexShader)
+ {
+ mDevice->SetVertexShader(vertexShader);
+ mAppliedVertexShader = vertexShader;
+ }
+
+ if (pixelShader != mAppliedPixelShader)
+ {
+ mDevice->SetPixelShader(pixelShader);
+ mAppliedPixelShader = pixelShader;
+ }
+
+ // D3D9 has a quirk where creating multiple shaders with the same content
+ // can return the same shader pointer. Because GL programs store different data
+ // per-program, checking the program serial guarantees we upload fresh
+ // uniform data even if our shader pointers are the same.
+ // https://code.google.com/p/angleproject/issues/detail?id=661
+ unsigned int programSerial = programD3D->getSerial();
+ if (programSerial != mAppliedProgramSerial)
+ {
+ programD3D->dirtyAllUniforms();
+ mStateManager.forceSetDXUniformsState();
+ mAppliedProgramSerial = programSerial;
+ }
+
+ return programD3D->applyUniforms(drawMode);
+}
+
+gl::Error Renderer9::applyUniforms(const ProgramD3D &programD3D,
+ GLenum /*drawMode*/,
+ const std::vector<D3DUniform *> &uniformArray)
+{
+ for (const D3DUniform *targetUniform : uniformArray)
+ {
+ if (!targetUniform->dirty)
+ continue;
+
+ GLfloat *f = (GLfloat *)targetUniform->data;
+ GLint *i = (GLint *)targetUniform->data;
+
+ switch (targetUniform->type)
+ {
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_EXTERNAL_OES:
+ break;
+ case GL_BOOL:
+ case GL_BOOL_VEC2:
+ case GL_BOOL_VEC3:
+ case GL_BOOL_VEC4:
+ applyUniformnbv(targetUniform, i);
+ break;
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT4:
+ applyUniformnfv(targetUniform, f);
+ break;
+ case GL_INT:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
+ applyUniformniv(targetUniform, i);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ // Driver uniforms
+ mStateManager.setShaderConstants();
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+void Renderer9::applyUniformnfv(const D3DUniform *targetUniform, const GLfloat *v)
+{
+ if (targetUniform->isReferencedByFragmentShader())
+ {
+ mDevice->SetPixelShaderConstantF(targetUniform->psRegisterIndex, v, targetUniform->registerCount);
+ }
+
+ if (targetUniform->isReferencedByVertexShader())
+ {
+ mDevice->SetVertexShaderConstantF(targetUniform->vsRegisterIndex, v, targetUniform->registerCount);
+ }
+}
+
+void Renderer9::applyUniformniv(const D3DUniform *targetUniform, const GLint *v)
+{
+ ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9);
+ GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4];
+
+ for (unsigned int i = 0; i < targetUniform->registerCount; i++)
+ {
+ vector[i][0] = (GLfloat)v[4 * i + 0];
+ vector[i][1] = (GLfloat)v[4 * i + 1];
+ vector[i][2] = (GLfloat)v[4 * i + 2];
+ vector[i][3] = (GLfloat)v[4 * i + 3];
+ }
+
+ applyUniformnfv(targetUniform, (GLfloat*)vector);
+}
+
+void Renderer9::applyUniformnbv(const D3DUniform *targetUniform, const GLint *v)
+{
+ ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9);
+ GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4];
+
+ for (unsigned int i = 0; i < targetUniform->registerCount; i++)
+ {
+ vector[i][0] = (v[4 * i + 0] == GL_FALSE) ? 0.0f : 1.0f;
+ vector[i][1] = (v[4 * i + 1] == GL_FALSE) ? 0.0f : 1.0f;
+ vector[i][2] = (v[4 * i + 2] == GL_FALSE) ? 0.0f : 1.0f;
+ vector[i][3] = (v[4 * i + 3] == GL_FALSE) ? 0.0f : 1.0f;
+ }
+
+ applyUniformnfv(targetUniform, (GLfloat*)vector);
+}
+
+gl::Error Renderer9::clear(const ClearParameters &clearParams,
+ const gl::FramebufferAttachment *colorBuffer,
+ const gl::FramebufferAttachment *depthStencilBuffer)
+{
+ if (clearParams.colorClearType != GL_FLOAT)
+ {
+ // Clearing buffers with non-float values is not supported by Renderer9 and ES 2.0
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+ }
+
+ bool clearColor = clearParams.clearColor[0];
+ for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++)
+ {
+ if (clearParams.clearColor[i] != clearColor)
+ {
+ // Clearing individual buffers other than buffer zero is not supported by Renderer9 and ES 2.0
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+ }
+ }
+
+ float depth = gl::clamp01(clearParams.depthClearValue);
+ DWORD stencil = clearParams.stencilClearValue & 0x000000FF;
+
+ unsigned int stencilUnmasked = 0x0;
+ if (clearParams.clearStencil && depthStencilBuffer->getStencilSize() > 0)
+ {
+ ASSERT(depthStencilBuffer != nullptr);
+
+ RenderTargetD3D *stencilRenderTarget = nullptr;
+ gl::Error error = depthStencilBuffer->getRenderTarget(&stencilRenderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ RenderTarget9 *stencilRenderTarget9 = GetAs<RenderTarget9>(stencilRenderTarget);
+ ASSERT(stencilRenderTarget9);
+
+ const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(stencilRenderTarget9->getD3DFormat());
+ stencilUnmasked = (0x1 << d3dFormatInfo.stencilBits) - 1;
+ }
+
+ const bool needMaskedStencilClear = clearParams.clearStencil &&
+ (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked;
+
+ bool needMaskedColorClear = false;
+ D3DCOLOR color = D3DCOLOR_ARGB(255, 0, 0, 0);
+ if (clearColor)
+ {
+ ASSERT(colorBuffer != nullptr);
+
+ RenderTargetD3D *colorRenderTarget = NULL;
+ gl::Error error = colorBuffer->getRenderTarget(&colorRenderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ RenderTarget9 *colorRenderTarget9 = GetAs<RenderTarget9>(colorRenderTarget);
+ ASSERT(colorRenderTarget9);
+
+ const gl::InternalFormat &formatInfo = *colorBuffer->getFormat().info;
+ const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(colorRenderTarget9->getD3DFormat());
+
+ color =
+ D3DCOLOR_ARGB(gl::unorm<8>((formatInfo.alphaBits == 0 && d3dFormatInfo.alphaBits > 0)
+ ? 1.0f
+ : clearParams.colorFClearValue.alpha),
+ gl::unorm<8>((formatInfo.redBits == 0 && d3dFormatInfo.redBits > 0)
+ ? 0.0f
+ : clearParams.colorFClearValue.red),
+ gl::unorm<8>((formatInfo.greenBits == 0 && d3dFormatInfo.greenBits > 0)
+ ? 0.0f
+ : clearParams.colorFClearValue.green),
+ gl::unorm<8>((formatInfo.blueBits == 0 && d3dFormatInfo.blueBits > 0)
+ ? 0.0f
+ : clearParams.colorFClearValue.blue));
+
+ if ((formatInfo.redBits > 0 && !clearParams.colorMaskRed) ||
+ (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) ||
+ (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) ||
+ (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha))
+ {
+ needMaskedColorClear = true;
+ }
+ }
+
+ if (needMaskedColorClear || needMaskedStencilClear)
+ {
+ // State which is altered in all paths from this point to the clear call is saved.
+ // State which is altered in only some paths will be flagged dirty in the case that
+ // that path is taken.
+ HRESULT hr;
+ if (mMaskedClearSavedState == NULL)
+ {
+ hr = mDevice->BeginStateBlock();
+ ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+
+ mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
+ mDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+ mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
+ mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
+ mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+ mDevice->SetPixelShader(NULL);
+ mDevice->SetVertexShader(NULL);
+ mDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
+ mDevice->SetStreamSource(0, NULL, 0, 0);
+ mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+ mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+ mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
+ mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+ mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
+ mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
+ mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+
+ for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ mDevice->SetStreamSourceFreq(i, 1);
+ }
+
+ hr = mDevice->EndStateBlock(&mMaskedClearSavedState);
+ ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+ }
+
+ ASSERT(mMaskedClearSavedState != NULL);
+
+ if (mMaskedClearSavedState != NULL)
+ {
+ hr = mMaskedClearSavedState->Capture();
+ ASSERT(SUCCEEDED(hr));
+ }
+
+ mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
+ mDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+ mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
+
+ if (clearColor)
+ {
+ mDevice->SetRenderState(D3DRS_COLORWRITEENABLE,
+ gl_d3d9::ConvertColorMask(clearParams.colorMaskRed,
+ clearParams.colorMaskGreen,
+ clearParams.colorMaskBlue,
+ clearParams.colorMaskAlpha));
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
+ }
+
+ if (stencilUnmasked != 0x0 && clearParams.clearStencil)
+ {
+ mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
+ mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
+ mDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
+ mDevice->SetRenderState(D3DRS_STENCILREF, stencil);
+ mDevice->SetRenderState(D3DRS_STENCILWRITEMASK, clearParams.stencilWriteMask);
+ mDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
+ mDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE);
+ mDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+ }
+
+ mDevice->SetPixelShader(NULL);
+ mDevice->SetVertexShader(NULL);
+ mDevice->SetFVF(D3DFVF_XYZRHW);
+ mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+ mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+ mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
+ mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+ mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
+ mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
+ mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+
+ for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ mDevice->SetStreamSourceFreq(i, 1);
+ }
+
+ int renderTargetWidth = mStateManager.getRenderTargetWidth();
+ int renderTargetHeight = mStateManager.getRenderTargetHeight();
+
+ float quad[4][4]; // A quadrilateral covering the target, aligned to match the edges
+ quad[0][0] = -0.5f;
+ quad[0][1] = renderTargetHeight - 0.5f;
+ quad[0][2] = 0.0f;
+ quad[0][3] = 1.0f;
+
+ quad[1][0] = renderTargetWidth - 0.5f;
+ quad[1][1] = renderTargetHeight - 0.5f;
+ quad[1][2] = 0.0f;
+ quad[1][3] = 1.0f;
+
+ quad[2][0] = -0.5f;
+ quad[2][1] = -0.5f;
+ quad[2][2] = 0.0f;
+ quad[2][3] = 1.0f;
+
+ quad[3][0] = renderTargetWidth - 0.5f;
+ quad[3][1] = -0.5f;
+ quad[3][2] = 0.0f;
+ quad[3][3] = 1.0f;
+
+ startScene();
+ mDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4]));
+
+ if (clearParams.clearDepth)
+ {
+ mDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
+ mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
+ mDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil);
+ }
+
+ if (mMaskedClearSavedState != NULL)
+ {
+ mMaskedClearSavedState->Apply();
+ }
+ }
+ else if (clearColor || clearParams.clearDepth || clearParams.clearStencil)
+ {
+ DWORD dxClearFlags = 0;
+ if (clearColor)
+ {
+ dxClearFlags |= D3DCLEAR_TARGET;
+ }
+ if (clearParams.clearDepth)
+ {
+ dxClearFlags |= D3DCLEAR_ZBUFFER;
+ }
+ if (clearParams.clearStencil)
+ {
+ dxClearFlags |= D3DCLEAR_STENCIL;
+ }
+
+ mDevice->Clear(0, NULL, dxClearFlags, color, depth, stencil);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+void Renderer9::markAllStateDirty()
+{
+ mAppliedRenderTargetSerial = 0;
+ mAppliedDepthStencilSerial = 0;
+ mDepthStencilInitialized = false;
+ mRenderTargetDescInitialized = false;
+
+ mStateManager.forceSetRasterState();
+ mStateManager.forceSetDepthStencilState();
+ mStateManager.forceSetBlendState();
+ mStateManager.forceSetScissorState();
+ mStateManager.forceSetViewportState();
+
+ ASSERT(mCurVertexSamplerStates.size() == mCurVertexTextures.size());
+ for (unsigned int i = 0; i < mCurVertexTextures.size(); i++)
+ {
+ mCurVertexSamplerStates[i].forceSet = true;
+ mCurVertexTextures[i] = angle::DirtyPointer;
+ }
+
+ ASSERT(mCurPixelSamplerStates.size() == mCurPixelTextures.size());
+ for (unsigned int i = 0; i < mCurPixelSamplerStates.size(); i++)
+ {
+ mCurPixelSamplerStates[i].forceSet = true;
+ mCurPixelTextures[i] = angle::DirtyPointer;
+ }
+
+ mAppliedIBSerial = 0;
+ mAppliedVertexShader = NULL;
+ mAppliedPixelShader = NULL;
+ mAppliedProgramSerial = 0;
+ mStateManager.forceSetDXUniformsState();
+
+ mVertexDeclarationCache.markStateDirty();
+}
+
+void Renderer9::releaseDeviceResources()
+{
+ for (size_t i = 0; i < mEventQueryPool.size(); i++)
+ {
+ SafeRelease(mEventQueryPool[i]);
+ }
+ mEventQueryPool.clear();
+
+ SafeRelease(mMaskedClearSavedState);
+
+ mVertexShaderCache.clear();
+ mPixelShaderCache.clear();
+
+ SafeDelete(mBlit);
+ SafeDelete(mVertexDataManager);
+ SafeDelete(mIndexDataManager);
+ SafeDelete(mLineLoopIB);
+ SafeDelete(mCountingIB);
+
+ for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
+ {
+ SafeDelete(mNullColorbufferCache[i].buffer);
+ }
+}
+
+// set notify to true to broadcast a message to all contexts of the device loss
+bool Renderer9::testDeviceLost()
+{
+ HRESULT status = getDeviceStatusCode();
+ return FAILED(status);
+}
+
+HRESULT Renderer9::getDeviceStatusCode()
+{
+ HRESULT status = D3D_OK;
+
+ if (mDeviceEx)
+ {
+ status = mDeviceEx->CheckDeviceState(NULL);
+ }
+ else if (mDevice)
+ {
+ status = mDevice->TestCooperativeLevel();
+ }
+
+ return status;
+}
+
+bool Renderer9::testDeviceResettable()
+{
+ // On D3D9Ex, DEVICELOST represents a hung device that needs to be restarted
+ // DEVICEREMOVED indicates the device has been stopped and must be recreated
+ switch (getDeviceStatusCode())
+ {
+ case D3DERR_DEVICENOTRESET:
+ case D3DERR_DEVICEHUNG:
+ return true;
+ case D3DERR_DEVICELOST:
+ return (mDeviceEx != NULL);
+ case D3DERR_DEVICEREMOVED:
+ ASSERT(mDeviceEx != NULL);
+ return isRemovedDeviceResettable();
+ default:
+ return false;
+ }
+}
+
+bool Renderer9::resetDevice()
+{
+ releaseDeviceResources();
+
+ D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
+
+ HRESULT result = D3D_OK;
+ bool lost = testDeviceLost();
+ bool removedDevice = (getDeviceStatusCode() == D3DERR_DEVICEREMOVED);
+
+ // Device Removed is a feature which is only present with D3D9Ex
+ ASSERT(mDeviceEx != NULL || !removedDevice);
+
+ for (int attempts = 3; lost && attempts > 0; attempts--)
+ {
+ if (removedDevice)
+ {
+ // Device removed, which may trigger on driver reinstallation,
+ // may cause a longer wait other reset attempts before the
+ // system is ready to handle creating a new device.
+ Sleep(800);
+ lost = !resetRemovedDevice();
+ }
+ else if (mDeviceEx)
+ {
+ Sleep(500); // Give the graphics driver some CPU time
+ result = mDeviceEx->ResetEx(&presentParameters, NULL);
+ lost = testDeviceLost();
+ }
+ else
+ {
+ result = mDevice->TestCooperativeLevel();
+ while (result == D3DERR_DEVICELOST)
+ {
+ Sleep(100); // Give the graphics driver some CPU time
+ result = mDevice->TestCooperativeLevel();
+ }
+
+ if (result == D3DERR_DEVICENOTRESET)
+ {
+ result = mDevice->Reset(&presentParameters);
+ }
+ lost = testDeviceLost();
+ }
+ }
+
+ if (FAILED(result))
+ {
+ ERR("Reset/ResetEx failed multiple times: 0x%08X", result);
+ return false;
+ }
+
+ if (removedDevice && lost)
+ {
+ ERR("Device lost reset failed multiple times");
+ return false;
+ }
+
+ // If the device was removed, we already finished re-initialization in resetRemovedDevice
+ if (!removedDevice)
+ {
+ // reset device defaults
+ initializeDevice();
+ }
+
+ return true;
+}
+
+bool Renderer9::isRemovedDeviceResettable() const
+{
+ bool success = false;
+
+#if ANGLE_D3D9EX == ANGLE_ENABLED
+ IDirect3D9Ex *d3d9Ex = NULL;
+ typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**);
+ Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast<Direct3DCreate9ExFunc>(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex"));
+
+ if (Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &d3d9Ex)))
+ {
+ D3DCAPS9 deviceCaps;
+ HRESULT result = d3d9Ex->GetDeviceCaps(mAdapter, mDeviceType, &deviceCaps);
+ success = SUCCEEDED(result);
+ }
+
+ SafeRelease(d3d9Ex);
+#else
+ ASSERT(UNREACHABLE());
+#endif
+
+ return success;
+}
+
+bool Renderer9::resetRemovedDevice()
+{
+ // From http://msdn.microsoft.com/en-us/library/windows/desktop/bb172554(v=vs.85).aspx:
+ // The hardware adapter has been removed. Application must destroy the device, do enumeration of
+ // adapters and create another Direct3D device. If application continues rendering without
+ // calling Reset, the rendering calls will succeed. Applies to Direct3D 9Ex only.
+ release();
+ return !initialize().isError();
+}
+
+VendorID Renderer9::getVendorId() const
+{
+ return static_cast<VendorID>(mAdapterIdentifier.VendorId);
+}
+
+std::string Renderer9::getRendererDescription() const
+{
+ std::ostringstream rendererString;
+
+ rendererString << mAdapterIdentifier.Description;
+ if (getShareHandleSupport())
+ {
+ rendererString << " Direct3D9Ex";
+ }
+ else
+ {
+ rendererString << " Direct3D9";
+ }
+
+ rendererString << " vs_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.VertexShaderVersion) << "_" << D3DSHADER_VERSION_MINOR(mDeviceCaps.VertexShaderVersion);
+ rendererString << " ps_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion) << "_" << D3DSHADER_VERSION_MINOR(mDeviceCaps.PixelShaderVersion);
+
+ return rendererString.str();
+}
+
+DeviceIdentifier Renderer9::getAdapterIdentifier() const
+{
+ DeviceIdentifier deviceIdentifier = { 0 };
+ deviceIdentifier.VendorId = static_cast<UINT>(mAdapterIdentifier.VendorId);
+ deviceIdentifier.DeviceId = static_cast<UINT>(mAdapterIdentifier.DeviceId);
+ deviceIdentifier.SubSysId = static_cast<UINT>(mAdapterIdentifier.SubSysId);
+ deviceIdentifier.Revision = static_cast<UINT>(mAdapterIdentifier.Revision);
+ deviceIdentifier.FeatureLevel = 0;
+
+ return deviceIdentifier;
+}
+
+unsigned int Renderer9::getReservedVertexUniformVectors() const
+{
+ return d3d9_gl::GetReservedVertexUniformVectors();
+}
+
+unsigned int Renderer9::getReservedFragmentUniformVectors() const
+{
+ return d3d9_gl::GetReservedFragmentUniformVectors();
+}
+
+unsigned int Renderer9::getReservedVertexUniformBuffers() const
+{
+ return 0;
+}
+
+unsigned int Renderer9::getReservedFragmentUniformBuffers() const
+{
+ return 0;
+}
+
+bool Renderer9::getShareHandleSupport() const
+{
+ // PIX doesn't seem to support using share handles, so disable them.
+ return (mD3d9Ex != NULL) && !gl::DebugAnnotationsActive();
+}
+
+int Renderer9::getMajorShaderModel() const
+{
+ return D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion);
+}
+
+int Renderer9::getMinorShaderModel() const
+{
+ return D3DSHADER_VERSION_MINOR(mDeviceCaps.PixelShaderVersion);
+}
+
+std::string Renderer9::getShaderModelSuffix() const
+{
+ return "";
+}
+
+DWORD Renderer9::getCapsDeclTypes() const
+{
+ return mDeviceCaps.DeclTypes;
+}
+
+D3DPOOL Renderer9::getBufferPool(DWORD usage) const
+{
+ if (mD3d9Ex != NULL)
+ {
+ return D3DPOOL_DEFAULT;
+ }
+ else
+ {
+ if (!(usage & D3DUSAGE_DYNAMIC))
+ {
+ return D3DPOOL_MANAGED;
+ }
+ }
+
+ return D3DPOOL_DEFAULT;
+}
+
+gl::Error Renderer9::copyImage2D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
+ const gl::Offset &destOffset, TextureStorage *storage, GLint level)
+{
+ RECT rect;
+ rect.left = sourceRect.x;
+ rect.top = sourceRect.y;
+ rect.right = sourceRect.x + sourceRect.width;
+ rect.bottom = sourceRect.y + sourceRect.height;
+
+ return mBlit->copy2D(framebuffer, rect, destFormat, destOffset, storage, level);
+}
+
+gl::Error Renderer9::copyImageCube(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
+ const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level)
+{
+ RECT rect;
+ rect.left = sourceRect.x;
+ rect.top = sourceRect.y;
+ rect.right = sourceRect.x + sourceRect.width;
+ rect.bottom = sourceRect.y + sourceRect.height;
+
+ return mBlit->copyCube(framebuffer, rect, destFormat, destOffset, storage, target, level);
+}
+
+gl::Error Renderer9::copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
+ const gl::Offset &destOffset, TextureStorage *storage, GLint level)
+{
+ // 3D textures are not available in the D3D9 backend.
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+gl::Error Renderer9::copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
+ const gl::Offset &destOffset, TextureStorage *storage, GLint level)
+{
+ // 2D array textures are not available in the D3D9 backend.
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+gl::Error Renderer9::copyTexture(const gl::Texture *source,
+ GLint sourceLevel,
+ const gl::Rectangle &sourceRect,
+ GLenum destFormat,
+ const gl::Offset &destOffset,
+ TextureStorage *storage,
+ GLint destLevel,
+ bool unpackFlipY,
+ bool unpackPremultiplyAlpha,
+ bool unpackUnmultiplyAlpha)
+{
+ UNIMPLEMENTED();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+gl::Error Renderer9::copyCompressedTexture(const gl::Texture *source,
+ GLint sourceLevel,
+ TextureStorage *storage,
+ GLint destLevel)
+{
+ UNIMPLEMENTED();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+gl::Error Renderer9::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT)
+{
+ const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(format);
+
+ const gl::TextureCaps &textureCaps = getNativeTextureCaps().get(format);
+ GLuint supportedSamples = textureCaps.getNearestSamples(samples);
+
+ IDirect3DTexture9 *texture = nullptr;
+ IDirect3DSurface9 *renderTarget = NULL;
+ if (width > 0 && height > 0)
+ {
+ bool requiresInitialization = false;
+ HRESULT result = D3DERR_INVALIDCALL;
+
+ const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
+ if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
+ {
+ result = mDevice->CreateDepthStencilSurface(width, height, d3d9FormatInfo.renderFormat,
+ gl_d3d9::GetMultisampleType(supportedSamples),
+ 0, FALSE, &renderTarget, NULL);
+ }
+ else
+ {
+ requiresInitialization = (d3d9FormatInfo.dataInitializerFunction != nullptr);
+ if (supportedSamples > 0)
+ {
+ result = mDevice->CreateRenderTarget(width, height, d3d9FormatInfo.renderFormat,
+ gl_d3d9::GetMultisampleType(supportedSamples),
+ 0, FALSE, &renderTarget, nullptr);
+ }
+ else
+ {
+ result = mDevice->CreateTexture(
+ width, height, 1, D3DUSAGE_RENDERTARGET, d3d9FormatInfo.texFormat,
+ getTexturePool(D3DUSAGE_RENDERTARGET), &texture, nullptr);
+ if (!FAILED(result))
+ {
+ result = texture->GetSurfaceLevel(0, &renderTarget);
+ }
+ }
+ }
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == E_INVALIDARG);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target, result: 0x%X.", result);
+ }
+
+ if (requiresInitialization)
+ {
+ // This format requires that the data be initialized before the render target can be used
+ // Unfortunately this requires a Get call on the d3d device but it is far better than having
+ // to mark the render target as lockable and copy data to the gpu.
+ IDirect3DSurface9 *prevRenderTarget = NULL;
+ mDevice->GetRenderTarget(0, &prevRenderTarget);
+ mDevice->SetRenderTarget(0, renderTarget);
+ mDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 0.0f, 0);
+ mDevice->SetRenderTarget(0, prevRenderTarget);
+ }
+ }
+
+ *outRT = new TextureRenderTarget9(texture, 0, renderTarget, format, width, height, 1,
+ supportedSamples);
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Renderer9::createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT)
+{
+ ASSERT(source != nullptr);
+
+ RenderTargetD3D *newRT = nullptr;
+ gl::Error error = createRenderTarget(source->getWidth(), source->getHeight(),
+ source->getInternalFormat(), source->getSamples(), &newRT);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ RenderTarget9 *source9 = GetAs<RenderTarget9>(source);
+ RenderTarget9 *dest9 = GetAs<RenderTarget9>(newRT);
+
+ HRESULT result = mDevice->StretchRect(source9->getSurface(), nullptr, dest9->getSurface(),
+ nullptr, D3DTEXF_NONE);
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to copy render target, result: 0x%X.", result);
+ }
+
+ *outRT = newRT;
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Renderer9::loadExecutable(const void *function,
+ size_t length,
+ ShaderType type,
+ const std::vector<D3DVarying> &streamOutVaryings,
+ bool separatedOutputBuffers,
+ ShaderExecutableD3D **outExecutable)
+{
+ // Transform feedback is not supported in ES2 or D3D9
+ ASSERT(streamOutVaryings.empty());
+
+ switch (type)
+ {
+ case SHADER_VERTEX:
+ {
+ IDirect3DVertexShader9 *vshader = NULL;
+ gl::Error error = createVertexShader((DWORD*)function, length, &vshader);
+ if (error.isError())
+ {
+ return error;
+ }
+ *outExecutable = new ShaderExecutable9(function, length, vshader);
+ }
+ break;
+ case SHADER_PIXEL:
+ {
+ IDirect3DPixelShader9 *pshader = NULL;
+ gl::Error error = createPixelShader((DWORD*)function, length, &pshader);
+ if (error.isError())
+ {
+ return error;
+ }
+ *outExecutable = new ShaderExecutable9(function, length, pshader);
+ }
+ break;
+ default:
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog,
+ const std::string &shaderHLSL,
+ ShaderType type,
+ const std::vector<D3DVarying> &streamOutVaryings,
+ bool separatedOutputBuffers,
+ const D3DCompilerWorkarounds &workarounds,
+ ShaderExecutableD3D **outExectuable)
+{
+ // Transform feedback is not supported in ES2 or D3D9
+ ASSERT(streamOutVaryings.empty());
+
+ const char *profileType = NULL;
+ switch (type)
+ {
+ case SHADER_VERTEX:
+ profileType = "vs";
+ break;
+ case SHADER_PIXEL:
+ profileType = "ps";
+ break;
+ default:
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+ }
+ unsigned int profileMajorVersion = (getMajorShaderModel() >= 3) ? 3 : 2;
+ unsigned int profileMinorVersion = 0;
+ std::string profile = FormatString("%s_%u_%u", profileType, profileMajorVersion, profileMinorVersion);
+
+ UINT flags = ANGLE_COMPILE_OPTIMIZATION_LEVEL;
+
+ if (workarounds.skipOptimization)
+ {
+ flags = D3DCOMPILE_SKIP_OPTIMIZATION;
+ }
+ else if (workarounds.useMaxOptimization)
+ {
+ flags = D3DCOMPILE_OPTIMIZATION_LEVEL3;
+ }
+
+ if (gl::DebugAnnotationsActive())
+ {
+#ifndef NDEBUG
+ flags = D3DCOMPILE_SKIP_OPTIMIZATION;
+#endif
+
+ flags |= D3DCOMPILE_DEBUG;
+ }
+
+ // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options.
+ // Try the default flags first and if compilation fails, try some alternatives.
+ std::vector<CompileConfig> configs;
+ configs.push_back(CompileConfig(flags, "default" ));
+ configs.push_back(CompileConfig(flags | D3DCOMPILE_AVOID_FLOW_CONTROL, "avoid flow control" ));
+ configs.push_back(CompileConfig(flags | D3DCOMPILE_PREFER_FLOW_CONTROL, "prefer flow control"));
+
+ ID3DBlob *binary = NULL;
+ std::string debugInfo;
+ gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, NULL, &binary, &debugInfo);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ // It's possible that binary is NULL if the compiler failed in all configurations. Set the executable to NULL
+ // and return GL_NO_ERROR to signify that there was a link error but the internal state is still OK.
+ if (!binary)
+ {
+ *outExectuable = NULL;
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type,
+ streamOutVaryings, separatedOutputBuffers, outExectuable);
+
+ SafeRelease(binary);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ if (!debugInfo.empty())
+ {
+ (*outExectuable)->appendDebugInfo(debugInfo);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+UniformStorageD3D *Renderer9::createUniformStorage(size_t storageSize)
+{
+ return new UniformStorageD3D(storageSize);
+}
+
+gl::Error Renderer9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest)
+{
+ return mBlit->boxFilter(source, dest);
+}
+
+D3DPOOL Renderer9::getTexturePool(DWORD usage) const
+{
+ // Always use DEFAULT pool for textures, as there is a bug
+ // on XP (non-D3D9Ex) where we select MANAGED here,
+ // but trigger a crash in Image9::copyToSurface where the
+ // source pool is SYSTEMMEM, but the destination pool is
+ // MANAGED. It expects the dest pool to be DEFAULT
+ // if the source is SYSTEMMEM.
+ return D3DPOOL_DEFAULT;
+}
+
+gl::Error Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged)
+{
+ ASSERT(source && dest);
+
+ HRESULT result = D3DERR_OUTOFVIDEOMEMORY;
+
+ if (fromManaged)
+ {
+ D3DSURFACE_DESC desc;
+ source->GetDesc(&desc);
+
+ IDirect3DSurface9 *surf = 0;
+ result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
+
+ if (SUCCEEDED(result))
+ {
+ Image9::copyLockableSurfaces(surf, source);
+ result = mDevice->UpdateSurface(surf, NULL, dest, NULL);
+ SafeRelease(surf);
+ }
+ }
+ else
+ {
+ endScene();
+ result = mDevice->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
+ }
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to blit internal texture, result: 0x%X.", result);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+ImageD3D *Renderer9::createImage()
+{
+ return new Image9(this);
+}
+
+gl::Error Renderer9::generateMipmap(ImageD3D *dest, ImageD3D *src)
+{
+ Image9 *src9 = GetAs<Image9>(src);
+ Image9 *dst9 = GetAs<Image9>(dest);
+ return Image9::generateMipmap(dst9, src9);
+}
+
+gl::Error Renderer9::generateMipmapUsingD3D(TextureStorage *storage,
+ const gl::TextureState &textureState)
+{
+ UNREACHABLE();
+ return gl::Error(GL_NO_ERROR);
+}
+
+TextureStorage *Renderer9::createTextureStorage2D(SwapChainD3D *swapChain)
+{
+ SwapChain9 *swapChain9 = GetAs<SwapChain9>(swapChain);
+ return new TextureStorage9_2D(this, swapChain9);
+}
+
+TextureStorage *Renderer9::createTextureStorageEGLImage(EGLImageD3D *eglImage,
+ RenderTargetD3D *renderTargetD3D)
+{
+ return new TextureStorage9_EGLImage(this, eglImage, GetAs<RenderTarget9>(renderTargetD3D));
+}
+
+TextureStorage *Renderer9::createTextureStorageExternal(
+ egl::Stream *stream,
+ const egl::Stream::GLTextureDescription &desc)
+{
+ UNIMPLEMENTED();
+ return nullptr;
+}
+
+TextureStorage *Renderer9::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly)
+{
+ return new TextureStorage9_2D(this, internalformat, renderTarget, width, height, levels);
+}
+
+TextureStorage *Renderer9::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly)
+{
+ return new TextureStorage9_Cube(this, internalformat, renderTarget, size, levels, hintLevelZeroOnly);
+}
+
+TextureStorage *Renderer9::createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels)
+{
+ // 3D textures are not supported by the D3D9 backend.
+ UNREACHABLE();
+
+ return NULL;
+}
+
+TextureStorage *Renderer9::createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels)
+{
+ // 2D array textures are not supported by the D3D9 backend.
+ UNREACHABLE();
+
+ return NULL;
+}
+
+bool Renderer9::getLUID(LUID *adapterLuid) const
+{
+ adapterLuid->HighPart = 0;
+ adapterLuid->LowPart = 0;
+
+ if (mD3d9Ex)
+ {
+ mD3d9Ex->GetAdapterLUID(mAdapter, adapterLuid);
+ return true;
+ }
+
+ return false;
+}
+
+VertexConversionType Renderer9::getVertexConversionType(gl::VertexFormatType vertexFormatType) const
+{
+ return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormatType).conversionType;
+}
+
+GLenum Renderer9::getVertexComponentType(gl::VertexFormatType vertexFormatType) const
+{
+ return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormatType).componentType;
+}
+
+gl::ErrorOrResult<unsigned int> Renderer9::getVertexSpaceRequired(const gl::VertexAttribute &attrib,
+ GLsizei count,
+ GLsizei instances) const
+{
+ gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib, GL_FLOAT);
+ const d3d9::VertexFormat &d3d9VertexInfo =
+ d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormatType);
+
+ if (!attrib.enabled)
+ {
+ return 16u;
+ }
+
+ unsigned int elementCount = 0;
+ if (instances == 0 || attrib.divisor == 0)
+ {
+ elementCount = static_cast<unsigned int>(count);
+ }
+ else
+ {
+ // Round up to divisor, if possible
+ elementCount = UnsignedCeilDivide(static_cast<unsigned int>(instances), attrib.divisor);
+ }
+
+ if (d3d9VertexInfo.outputElementSize > std::numeric_limits<unsigned int>::max() / elementCount)
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "New vertex buffer size would result in an overflow.");
+ }
+
+ return static_cast<unsigned int>(d3d9VertexInfo.outputElementSize) * elementCount;
+}
+
+void Renderer9::generateCaps(gl::Caps *outCaps,
+ gl::TextureCapsMap *outTextureCaps,
+ gl::Extensions *outExtensions,
+ gl::Limitations *outLimitations) const
+{
+ d3d9_gl::GenerateCaps(mD3d9, mDevice, mDeviceType, mAdapter, outCaps, outTextureCaps,
+ outExtensions, outLimitations);
+}
+
+WorkaroundsD3D Renderer9::generateWorkarounds() const
+{
+ return d3d9::GenerateWorkarounds();
+}
+
+gl::Error Renderer9::clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd)
+{
+ // TODO(jmadill): faster way?
+ for (size_t samplerIndex = rangeStart; samplerIndex < rangeEnd; samplerIndex++)
+ {
+ gl::Error error = setTexture(samplerType, static_cast<int>(samplerIndex), nullptr);
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+egl::Error Renderer9::getEGLDevice(DeviceImpl **device)
+{
+ if (mEGLDevice == nullptr)
+ {
+ ASSERT(mDevice != nullptr);
+ mEGLDevice = new DeviceD3D();
+ egl::Error error = mEGLDevice->initialize(reinterpret_cast<void *>(mDevice),
+ EGL_D3D9_DEVICE_ANGLE, EGL_FALSE);
+
+ if (error.isError())
+ {
+ SafeDelete(mEGLDevice);
+ return error;
+ }
+ }
+
+ *device = static_cast<DeviceImpl *>(mEGLDevice);
+ return egl::Error(EGL_SUCCESS);
+}
+
+Renderer9::CurSamplerState::CurSamplerState()
+ : forceSet(true),
+ baseLevel(std::numeric_limits<size_t>::max()),
+ samplerState()
+{
+}
+
+gl::Error Renderer9::genericDrawElements(Context9 *context,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances,
+ const gl::IndexRange &indexRange)
+{
+ const auto &data = context->getContextState();
+ gl::Program *program = context->getGLState().getProgram();
+ ASSERT(program != nullptr);
+ ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
+ bool usesPointSize = programD3D->usesPointSize();
+
+ programD3D->updateSamplerMapping();
+
+ if (!applyPrimitiveType(mode, count, usesPointSize))
+ {
+ return gl::NoError();
+ }
+
+ ANGLE_TRY(updateState(context, mode));
+
+ TranslatedIndexData indexInfo;
+ indexInfo.indexRange = indexRange;
+
+ ANGLE_TRY(applyIndexBuffer(data, indices, count, mode, type, &indexInfo));
+
+ applyTransformFeedbackBuffers(data.getState());
+ // Transform feedback is not allowed for DrawElements, this error should have been caught at the
+ // API validation
+ // layer.
+ ASSERT(!data.getState().isTransformFeedbackActiveUnpaused());
+
+ size_t vertexCount = indexInfo.indexRange.vertexCount();
+ ANGLE_TRY(applyVertexBuffer(data.getState(), mode,
+ static_cast<GLsizei>(indexInfo.indexRange.start),
+ static_cast<GLsizei>(vertexCount), instances, &indexInfo));
+ ANGLE_TRY(applyTextures(context, data));
+ ANGLE_TRY(applyShaders(data, mode));
+ ANGLE_TRY(programD3D->applyUniformBuffers(data));
+
+ if (!skipDraw(data, mode))
+ {
+ ANGLE_TRY(drawElementsImpl(data, indexInfo, mode, count, type, indices, instances));
+ }
+
+ return gl::NoError();
+}
+
+gl::Error Renderer9::genericDrawArrays(Context9 *context,
+ GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei instances)
+{
+ const auto &data = context->getContextState();
+ gl::Program *program = context->getGLState().getProgram();
+ ASSERT(program != nullptr);
+ ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
+ bool usesPointSize = programD3D->usesPointSize();
+
+ programD3D->updateSamplerMapping();
+
+ if (!applyPrimitiveType(mode, count, usesPointSize))
+ {
+ return gl::NoError();
+ }
+
+ ANGLE_TRY(updateState(context, mode));
+ ANGLE_TRY(applyTransformFeedbackBuffers(data.getState()));
+ ANGLE_TRY(applyVertexBuffer(data.getState(), mode, first, count, instances, nullptr));
+ ANGLE_TRY(applyTextures(context, data));
+ ANGLE_TRY(applyShaders(data, mode));
+ ANGLE_TRY(programD3D->applyUniformBuffers(data));
+
+ if (!skipDraw(data, mode))
+ {
+ ANGLE_TRY(drawArraysImpl(data, mode, first, count, instances));
+
+ if (data.getState().isTransformFeedbackActiveUnpaused())
+ {
+ ANGLE_TRY(markTransformFeedbackUsage(data));
+ }
+ }
+
+ return gl::NoError();
+}
+
+FramebufferImpl *Renderer9::createDefaultFramebuffer(const gl::FramebufferState &state)
+{
+ return new Framebuffer9(state, this);
+}
+
+gl::Version Renderer9::getMaxSupportedESVersion() const
+{
+ return gl::Version(2, 0);
+}
+
+} // namespace rx
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
new file mode 100755
index 000000000..9c3ae8b04
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
@@ -0,0 +1,487 @@
+//
+// Copyright (c) 2012-2014 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.
+//
+
+// Renderer9.h: Defines a back-end specific class for the D3D9 renderer.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_RENDERER9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_RENDERER9_H_
+
+#include "common/angleutils.h"
+#include "common/mathutil.h"
+#include "libANGLE/renderer/d3d/HLSLCompiler.h"
+#include "libANGLE/renderer/d3d/RendererD3D.h"
+#include "libANGLE/renderer/d3d/RenderTargetD3D.h"
+#include "libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h"
+#include "libANGLE/renderer/d3d/d3d9/ShaderCache.h"
+#include "libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h"
+#include "libANGLE/renderer/d3d/d3d9/StateManager9.h"
+#include "libANGLE/renderer/driver_utils.h"
+
+namespace gl
+{
+class FramebufferAttachment;
+}
+
+namespace egl
+{
+class AttributeMap;
+}
+
+namespace rx
+{
+class Blit9;
+class Context9;
+class IndexDataManager;
+class ProgramD3D;
+class StreamingIndexBufferInterface;
+class StaticIndexBufferInterface;
+class VertexDataManager;
+struct ClearParameters;
+struct D3DUniform;
+struct TranslatedAttribute;
+
+enum D3D9InitError
+{
+ D3D9_INIT_SUCCESS = 0,
+ // Failed to load the D3D or ANGLE compiler
+ D3D9_INIT_COMPILER_ERROR,
+ // Failed to load a necessary DLL
+ D3D9_INIT_MISSING_DEP,
+ // Device creation error
+ D3D9_INIT_CREATE_DEVICE_ERROR,
+ // System does not meet minimum shader spec
+ D3D9_INIT_UNSUPPORTED_VERSION,
+ // System does not support stretchrect from textures
+ D3D9_INIT_UNSUPPORTED_STRETCHRECT,
+ // A call returned out of memory or device lost
+ D3D9_INIT_OUT_OF_MEMORY,
+ // Other unspecified error
+ D3D9_INIT_OTHER_ERROR,
+ NUM_D3D9_INIT_ERRORS
+};
+
+class Renderer9 : public RendererD3D
+{
+ public:
+ explicit Renderer9(egl::Display *display);
+ virtual ~Renderer9();
+
+ egl::Error initialize() override;
+ bool resetDevice() override;
+
+ egl::ConfigSet generateConfigs() override;
+ void generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const override;
+
+ void startScene();
+ void endScene();
+
+ gl::Error flush();
+ gl::Error finish();
+
+ bool isValidNativeWindow(EGLNativeWindowType window) const override;
+ NativeWindowD3D *createNativeWindow(EGLNativeWindowType window,
+ const egl::Config *config,
+ const egl::AttributeMap &attribs) const override;
+
+ SwapChainD3D *createSwapChain(NativeWindowD3D *nativeWindow,
+ HANDLE shareHandle,
+ IUnknown *d3dTexture,
+ GLenum backBufferFormat,
+ GLenum depthBufferFormat,
+ EGLint orientation) override;
+ egl::Error getD3DTextureInfo(IUnknown *d3dTexture,
+ EGLint *width,
+ EGLint *height,
+ GLenum *fboFormat) const override;
+ egl::Error validateShareHandle(const egl::Config *config,
+ HANDLE shareHandle,
+ const egl::AttributeMap &attribs) const override;
+
+ ContextImpl *createContext(const gl::ContextState &state) override;
+
+ gl::Error allocateEventQuery(IDirect3DQuery9 **outQuery);
+ void freeEventQuery(IDirect3DQuery9* query);
+
+ // resource creation
+ gl::Error createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader);
+ gl::Error createPixelShader(const DWORD *function, size_t length, IDirect3DPixelShader9 **outShader);
+ HRESULT createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer);
+ HRESULT createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer);
+ gl::Error setSamplerState(gl::SamplerType type,
+ int index,
+ gl::Texture *texture,
+ const gl::SamplerState &sampler) override;
+ gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture) override;
+
+ gl::Error setUniformBuffers(const gl::ContextState &data,
+ const std::vector<GLint> &vertexUniformBuffers,
+ const std::vector<GLint> &fragmentUniformBuffers) override;
+
+ gl::Error updateState(Context9 *context, GLenum drawMode);
+
+ void setScissorRectangle(const gl::Rectangle &scissor, bool enabled);
+ void setViewport(const gl::Rectangle &viewport,
+ float zNear,
+ float zFar,
+ GLenum drawMode,
+ GLenum frontFace,
+ bool ignoreViewport);
+
+ gl::Error applyRenderTarget(GLImplFactory *implFactory, const gl::Framebuffer *frameBuffer);
+ gl::Error applyRenderTarget(GLImplFactory *implFactory,
+ const gl::FramebufferAttachment *colorAttachment,
+ const gl::FramebufferAttachment *depthStencilAttachment);
+ gl::Error applyUniforms(const ProgramD3D &programD3D,
+ GLenum drawMode,
+ const std::vector<D3DUniform *> &uniformArray) override;
+ bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize);
+ gl::Error applyVertexBuffer(const gl::State &state,
+ GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei instances,
+ TranslatedIndexData *indexInfo);
+ gl::Error applyIndexBuffer(const gl::ContextState &data,
+ const GLvoid *indices,
+ GLsizei count,
+ GLenum mode,
+ GLenum type,
+ TranslatedIndexData *indexInfo);
+
+ gl::Error applyTransformFeedbackBuffers(const gl::State &state);
+
+ gl::Error clear(const ClearParameters &clearParams,
+ const gl::FramebufferAttachment *colorBuffer,
+ const gl::FramebufferAttachment *depthStencilBuffer);
+
+ void markAllStateDirty();
+
+ // lost device
+ bool testDeviceLost() override;
+ bool testDeviceResettable();
+
+ VendorID getVendorId() const;
+ std::string getRendererDescription() const;
+ DeviceIdentifier getAdapterIdentifier() const override;
+
+ IDirect3DDevice9 *getDevice() { return mDevice; }
+ void *getD3DDevice() override;
+
+ unsigned int getReservedVertexUniformVectors() const;
+ unsigned int getReservedFragmentUniformVectors() const;
+ unsigned int getReservedVertexUniformBuffers() const override;
+ unsigned int getReservedFragmentUniformBuffers() const override;
+
+ bool getShareHandleSupport() const;
+
+ int getMajorShaderModel() const override;
+ int getMinorShaderModel() const override;
+ std::string getShaderModelSuffix() const override;
+
+ DWORD getCapsDeclTypes() const;
+
+ // Pixel operations
+ gl::Error copyImage2D(const gl::Framebuffer *framebuffer,
+ const gl::Rectangle &sourceRect,
+ GLenum destFormat,
+ const gl::Offset &destOffset,
+ TextureStorage *storage,
+ GLint level) override;
+ gl::Error copyImageCube(const gl::Framebuffer *framebuffer,
+ const gl::Rectangle &sourceRect,
+ GLenum destFormat,
+ const gl::Offset &destOffset,
+ TextureStorage *storage,
+ GLenum target,
+ GLint level) override;
+ gl::Error copyImage3D(const gl::Framebuffer *framebuffer,
+ const gl::Rectangle &sourceRect,
+ GLenum destFormat,
+ const gl::Offset &destOffset,
+ TextureStorage *storage,
+ GLint level) override;
+ gl::Error copyImage2DArray(const gl::Framebuffer *framebuffer,
+ const gl::Rectangle &sourceRect,
+ GLenum destFormat,
+ const gl::Offset &destOffset,
+ TextureStorage *storage,
+ GLint level) override;
+
+ gl::Error copyTexture(const gl::Texture *source,
+ GLint sourceLevel,
+ const gl::Rectangle &sourceRect,
+ GLenum destFormat,
+ const gl::Offset &destOffset,
+ TextureStorage *storage,
+ GLint destLevel,
+ bool unpackFlipY,
+ bool unpackPremultiplyAlpha,
+ bool unpackUnmultiplyAlpha) override;
+ gl::Error copyCompressedTexture(const gl::Texture *source,
+ GLint sourceLevel,
+ TextureStorage *storage,
+ GLint destLevel) override;
+
+ // RenderTarget creation
+ gl::Error createRenderTarget(int width,
+ int height,
+ GLenum format,
+ GLsizei samples,
+ RenderTargetD3D **outRT) override;
+ gl::Error createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT) override;
+
+ // Shader operations
+ gl::Error loadExecutable(const void *function,
+ size_t length,
+ ShaderType type,
+ const std::vector<D3DVarying> &streamOutVaryings,
+ bool separatedOutputBuffers,
+ ShaderExecutableD3D **outExecutable) override;
+ gl::Error compileToExecutable(gl::InfoLog &infoLog,
+ const std::string &shaderHLSL,
+ ShaderType type,
+ const std::vector<D3DVarying> &streamOutVaryings,
+ bool separatedOutputBuffers,
+ const D3DCompilerWorkarounds &workarounds,
+ ShaderExecutableD3D **outExectuable) override;
+ UniformStorageD3D *createUniformStorage(size_t storageSize) override;
+
+ // Image operations
+ ImageD3D *createImage() override;
+ gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) override;
+ gl::Error generateMipmapUsingD3D(TextureStorage *storage,
+ const gl::TextureState &textureState) override;
+ TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) override;
+ TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage,
+ RenderTargetD3D *renderTargetD3D) override;
+ TextureStorage *createTextureStorageExternal(
+ egl::Stream *stream,
+ const egl::Stream::GLTextureDescription &desc) override;
+ TextureStorage *createTextureStorage2D(GLenum internalformat,
+ bool renderTarget,
+ GLsizei width,
+ GLsizei height,
+ int levels,
+ bool hintLevelZeroOnly) override;
+ TextureStorage *createTextureStorageCube(GLenum internalformat,
+ bool renderTarget,
+ int size,
+ int levels,
+ bool hintLevelZeroOnly) override;
+ TextureStorage *createTextureStorage3D(GLenum internalformat,
+ bool renderTarget,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ int levels) override;
+ TextureStorage *createTextureStorage2DArray(GLenum internalformat,
+ bool renderTarget,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ int levels) override;
+
+ // Buffer creation
+ VertexBuffer *createVertexBuffer() override;
+ IndexBuffer *createIndexBuffer() override;
+
+ // Stream Creation
+ StreamProducerImpl *createStreamProducerD3DTextureNV12(
+ egl::Stream::ConsumerType consumerType,
+ const egl::AttributeMap &attribs) override;
+
+ // Buffer-to-texture and Texture-to-buffer copies
+ bool supportsFastCopyBufferToTexture(GLenum internalFormat) const override;
+ gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack,
+ unsigned int offset,
+ RenderTargetD3D *destRenderTarget,
+ GLenum destinationFormat,
+ GLenum sourcePixelsType,
+ const gl::Box &destArea) override;
+
+ // D3D9-renderer specific methods
+ gl::Error boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest);
+
+ D3DPOOL getTexturePool(DWORD usage) const;
+
+ bool getLUID(LUID *adapterLuid) const override;
+ VertexConversionType getVertexConversionType(gl::VertexFormatType vertexFormatType) const override;
+ GLenum getVertexComponentType(gl::VertexFormatType vertexFormatType) const override;
+ gl::ErrorOrResult<unsigned int> getVertexSpaceRequired(const gl::VertexAttribute &attrib,
+ GLsizei count,
+ GLsizei instances) const override;
+
+ gl::Error copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged);
+
+ RendererClass getRendererClass() const override { return RENDERER_D3D9; }
+
+ D3DDEVTYPE getD3D9DeviceType() const { return mDeviceType; }
+
+ egl::Error getEGLDevice(DeviceImpl **device) override;
+
+ StateManager9 *getStateManager() { return &mStateManager; }
+
+ gl::Error genericDrawArrays(Context9 *context,
+ GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei instances);
+
+ gl::Error genericDrawElements(Context9 *context,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances,
+ const gl::IndexRange &indexRange);
+
+ // Necessary hack for default framebuffers in D3D.
+ FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) override;
+
+ DebugAnnotator9 *getAnnotator() { return &mAnnotator; }
+
+ gl::Version getMaxSupportedESVersion() const override;
+
+ protected:
+ gl::Error clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) override;
+
+ private:
+ gl::Error drawArraysImpl(const gl::ContextState &data,
+ GLenum mode,
+ GLint startVertex,
+ GLsizei count,
+ GLsizei instances);
+ gl::Error drawElementsImpl(const gl::ContextState &data,
+ const TranslatedIndexData &indexInfo,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances);
+
+ gl::Error applyShaders(const gl::ContextState &data, GLenum drawMode);
+
+ void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps,
+ gl::Extensions *outExtensions,
+ gl::Limitations *outLimitations) const override;
+
+ WorkaroundsD3D generateWorkarounds() const override;
+
+ gl::Error setBlendDepthRasterStates(const gl::ContextState &glData, GLenum drawMode);
+
+ void release();
+
+ void applyUniformnfv(const D3DUniform *targetUniform, const GLfloat *v);
+ void applyUniformniv(const D3DUniform *targetUniform, const GLint *v);
+ void applyUniformnbv(const D3DUniform *targetUniform, const GLint *v);
+
+ gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer);
+ gl::Error drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer);
+
+ gl::Error getCountingIB(size_t count, StaticIndexBufferInterface **outIB);
+
+ gl::Error getNullColorbuffer(GLImplFactory *implFactory,
+ const gl::FramebufferAttachment *depthbuffer,
+ const gl::FramebufferAttachment **outColorBuffer);
+
+ D3DPOOL getBufferPool(DWORD usage) const;
+
+ HMODULE mD3d9Module;
+
+ void initializeDevice();
+ D3DPRESENT_PARAMETERS getDefaultPresentParameters();
+ void releaseDeviceResources();
+
+ HRESULT getDeviceStatusCode();
+ bool isRemovedDeviceResettable() const;
+ bool resetRemovedDevice();
+
+ UINT mAdapter;
+ D3DDEVTYPE mDeviceType;
+ IDirect3D9 *mD3d9; // Always valid after successful initialization.
+ IDirect3D9Ex *mD3d9Ex; // Might be null if D3D9Ex is not supported.
+ IDirect3DDevice9 *mDevice;
+ IDirect3DDevice9Ex *mDeviceEx; // Might be null if D3D9Ex is not supported.
+
+ HLSLCompiler mCompiler;
+
+ Blit9 *mBlit;
+
+ HWND mDeviceWindow;
+
+ D3DCAPS9 mDeviceCaps;
+ D3DADAPTER_IDENTIFIER9 mAdapterIdentifier;
+
+ D3DPRIMITIVETYPE mPrimitiveType;
+ int mPrimitiveCount;
+ GLsizei mRepeatDraw;
+
+ bool mSceneStarted;
+
+ bool mVertexTextureSupport;
+
+ // current render target states
+ unsigned int mAppliedRenderTargetSerial;
+ unsigned int mAppliedDepthStencilSerial;
+ bool mDepthStencilInitialized;
+ bool mRenderTargetDescInitialized;
+
+ IDirect3DStateBlock9 *mMaskedClearSavedState;
+
+ StateManager9 mStateManager;
+
+ // Currently applied sampler states
+ struct CurSamplerState
+ {
+ CurSamplerState();
+
+ bool forceSet;
+ size_t baseLevel;
+ gl::SamplerState samplerState;
+ };
+ std::vector<CurSamplerState> mCurVertexSamplerStates;
+ std::vector<CurSamplerState> mCurPixelSamplerStates;
+
+ // Currently applied textures
+ std::vector<uintptr_t> mCurVertexTextures;
+ std::vector<uintptr_t> mCurPixelTextures;
+
+ unsigned int mAppliedIBSerial;
+ IDirect3DVertexShader9 *mAppliedVertexShader;
+ IDirect3DPixelShader9 *mAppliedPixelShader;
+ unsigned int mAppliedProgramSerial;
+
+ // A pool of event queries that are currently unused.
+ std::vector<IDirect3DQuery9*> mEventQueryPool;
+ VertexShaderCache mVertexShaderCache;
+ PixelShaderCache mPixelShaderCache;
+
+ VertexDataManager *mVertexDataManager;
+ VertexDeclarationCache mVertexDeclarationCache;
+
+ IndexDataManager *mIndexDataManager;
+ StreamingIndexBufferInterface *mLineLoopIB;
+ StaticIndexBufferInterface *mCountingIB;
+
+ enum { NUM_NULL_COLORBUFFER_CACHE_ENTRIES = 12 };
+ struct NullColorbufferCacheEntry
+ {
+ UINT lruCount;
+ int width;
+ int height;
+ gl::FramebufferAttachment *buffer;
+ } mNullColorbufferCache[NUM_NULL_COLORBUFFER_CACHE_ENTRIES];
+ UINT mMaxNullColorbufferLRU;
+
+ DeviceD3D *mEGLDevice;
+ std::vector<TranslatedAttribute> mTranslatedAttribCache;
+
+ DebugAnnotator9 mAnnotator;
+};
+
+} // namespace rx
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_RENDERER9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h
new file mode 100755
index 000000000..cf831c62f
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h
@@ -0,0 +1,108 @@
+//
+// Copyright (c) 2012 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.
+//
+
+// ShaderCache: Defines rx::ShaderCache, a cache of Direct3D shader objects
+// keyed by their byte code.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_SHADERCACHE_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_SHADERCACHE_H_
+
+#include "libANGLE/Error.h"
+
+#include "common/debug.h"
+
+#include <cstddef>
+#include <unordered_map>
+#include <string>
+
+namespace rx
+{
+template <typename ShaderObject>
+class ShaderCache : angle::NonCopyable
+{
+ public:
+ ShaderCache() : mDevice(NULL)
+ {
+ }
+
+ ~ShaderCache()
+ {
+ // Call clear while the device is still valid.
+ ASSERT(mMap.empty());
+ }
+
+ void initialize(IDirect3DDevice9* device)
+ {
+ mDevice = device;
+ }
+
+ gl::Error create(const DWORD *function, size_t length, ShaderObject **outShaderObject)
+ {
+ std::string key(reinterpret_cast<const char*>(function), length);
+ typename Map::iterator it = mMap.find(key);
+ if (it != mMap.end())
+ {
+ it->second->AddRef();
+ *outShaderObject = it->second;
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ ShaderObject *shader;
+ HRESULT result = createShader(function, &shader);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create shader, result: 0x%X.", result);
+ }
+
+ // Random eviction policy.
+ if (mMap.size() >= kMaxMapSize)
+ {
+ SafeRelease(mMap.begin()->second);
+ mMap.erase(mMap.begin());
+ }
+
+ shader->AddRef();
+ mMap[key] = shader;
+
+ *outShaderObject = shader;
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ void clear()
+ {
+ for (typename Map::iterator it = mMap.begin(); it != mMap.end(); ++it)
+ {
+ SafeRelease(it->second);
+ }
+
+ mMap.clear();
+ }
+
+ private:
+ const static size_t kMaxMapSize = 100;
+
+ HRESULT createShader(const DWORD *function, IDirect3DVertexShader9 **shader)
+ {
+ return mDevice->CreateVertexShader(function, shader);
+ }
+
+ HRESULT createShader(const DWORD *function, IDirect3DPixelShader9 **shader)
+ {
+ return mDevice->CreatePixelShader(function, shader);
+ }
+
+ typedef std::unordered_map<std::string, ShaderObject*> Map;
+ Map mMap;
+
+ IDirect3DDevice9 *mDevice;
+};
+
+typedef ShaderCache<IDirect3DVertexShader9> VertexShaderCache;
+typedef ShaderCache<IDirect3DPixelShader9> PixelShaderCache;
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_SHADERCACHE_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp
new file mode 100755
index 000000000..dcce8fd2f
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp
@@ -0,0 +1,47 @@
+//
+// Copyright (c) 2012-2013 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.
+//
+
+// ShaderExecutable9.cpp: Implements a D3D9-specific class to contain shader
+// executable implementation details.
+
+#include "libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h"
+
+#include "common/debug.h"
+
+namespace rx
+{
+
+ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirect3DPixelShader9 *executable)
+ : ShaderExecutableD3D(function, length)
+{
+ mPixelExecutable = executable;
+ mVertexExecutable = NULL;
+}
+
+ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable)
+ : ShaderExecutableD3D(function, length)
+{
+ mVertexExecutable = executable;
+ mPixelExecutable = NULL;
+}
+
+ShaderExecutable9::~ShaderExecutable9()
+{
+ SafeRelease(mVertexExecutable);
+ SafeRelease(mPixelExecutable);
+}
+
+IDirect3DVertexShader9 *ShaderExecutable9::getVertexShader() const
+{
+ return mVertexExecutable;
+}
+
+IDirect3DPixelShader9 *ShaderExecutable9::getPixelShader() const
+{
+ return mPixelExecutable;
+}
+
+}
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h
new file mode 100755
index 000000000..382a68c82
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h
@@ -0,0 +1,35 @@
+//
+// Copyright (c) 2012-2013 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.
+//
+
+// ShaderExecutable9.h: Defines a D3D9-specific class to contain shader
+// executable implementation details.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_SHADEREXECUTABLE9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_SHADEREXECUTABLE9_H_
+
+#include "libANGLE/renderer/d3d/ShaderExecutableD3D.h"
+
+namespace rx
+{
+
+class ShaderExecutable9 : public ShaderExecutableD3D
+{
+ public:
+ ShaderExecutable9(const void *function, size_t length, IDirect3DPixelShader9 *executable);
+ ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable);
+ virtual ~ShaderExecutable9();
+
+ IDirect3DPixelShader9 *getPixelShader() const;
+ IDirect3DVertexShader9 *getVertexShader() const;
+
+ private:
+ IDirect3DPixelShader9 *mPixelExecutable;
+ IDirect3DVertexShader9 *mVertexExecutable;
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_SHADEREXECUTABLE9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp
new file mode 100755
index 000000000..54885bf81
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp
@@ -0,0 +1,945 @@
+//
+// Copyright (c) 2015 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.
+//
+
+// StateManager9.cpp: Defines a class for caching D3D9 state
+#include "libANGLE/renderer/d3d/d3d9/StateManager9.h"
+
+#include "common/BitSetIterator.h"
+#include "common/utilities.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
+#include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+
+namespace rx
+{
+
+StateManager9::StateManager9(Renderer9 *renderer9)
+ : mUsingZeroColorMaskWorkaround(false),
+ mCurBlendState(),
+ mCurBlendColor(0, 0, 0, 0),
+ mCurSampleMask(0),
+ mCurRasterState(),
+ mCurDepthSize(0),
+ mCurDepthStencilState(),
+ mCurStencilRef(0),
+ mCurStencilBackRef(0),
+ mCurFrontFaceCCW(0),
+ mCurStencilSize(0),
+ mCurScissorRect(),
+ mCurScissorEnabled(false),
+ mCurViewport(),
+ mCurNear(0.0f),
+ mCurFar(0.0f),
+ mCurDepthFront(0.0f),
+ mCurIgnoreViewport(false),
+ mRenderer9(renderer9),
+ mDirtyBits()
+{
+ mBlendStateDirtyBits.set(DIRTY_BIT_BLEND_ENABLED);
+ mBlendStateDirtyBits.set(DIRTY_BIT_BLEND_COLOR);
+ mBlendStateDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS);
+ mBlendStateDirtyBits.set(DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE);
+ mBlendStateDirtyBits.set(DIRTY_BIT_COLOR_MASK);
+ mBlendStateDirtyBits.set(DIRTY_BIT_DITHER);
+ mBlendStateDirtyBits.set(DIRTY_BIT_SAMPLE_MASK);
+
+ mRasterizerStateDirtyBits.set(DIRTY_BIT_CULL_MODE);
+ mRasterizerStateDirtyBits.set(DIRTY_BIT_DEPTH_BIAS);
+
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_MASK);
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_FUNC);
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_TEST_ENABLED);
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_FRONT);
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_BACK);
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK);
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_OPS_FRONT);
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_OPS_BACK);
+
+ mScissorStateDirtyBits.set(DIRTY_BIT_SCISSOR_ENABLED);
+ mScissorStateDirtyBits.set(DIRTY_BIT_SCISSOR_RECT);
+}
+
+StateManager9::~StateManager9()
+{
+}
+
+void StateManager9::initialize()
+{
+ mUsingZeroColorMaskWorkaround = IsAMD(mRenderer9->getVendorId());
+}
+
+void StateManager9::forceSetBlendState()
+{
+ mDirtyBits |= mBlendStateDirtyBits;
+}
+
+void StateManager9::forceSetRasterState()
+{
+ mDirtyBits |= mRasterizerStateDirtyBits;
+}
+
+void StateManager9::forceSetDepthStencilState()
+{
+ mDirtyBits |= mDepthStencilStateDirtyBits;
+}
+
+void StateManager9::forceSetScissorState()
+{
+ mDirtyBits |= mScissorStateDirtyBits;
+}
+
+void StateManager9::forceSetViewportState()
+{
+ mForceSetViewport = true;
+}
+
+void StateManager9::forceSetDXUniformsState()
+{
+ mDxUniformsDirty = true;
+}
+
+void StateManager9::updateStencilSizeIfChanged(bool depthStencilInitialized,
+ unsigned int stencilSize)
+{
+ if (!depthStencilInitialized || stencilSize != mCurStencilSize)
+ {
+ mCurStencilSize = stencilSize;
+ forceSetDepthStencilState();
+ }
+}
+
+void StateManager9::syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits)
+{
+ if (!dirtyBits.any())
+ {
+ return;
+ }
+
+ for (auto dirtyBit : angle::IterateBitSet(dirtyBits))
+ {
+ switch (dirtyBit)
+ {
+ case gl::State::DIRTY_BIT_BLEND_ENABLED:
+ if (state.getBlendState().blend != mCurBlendState.blend)
+ {
+ mDirtyBits.set(DIRTY_BIT_BLEND_ENABLED);
+ // BlendColor and funcs and equations has to be set if blend is enabled
+ mDirtyBits.set(DIRTY_BIT_BLEND_COLOR);
+ mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS);
+
+ // The color mask may have to be updated if the blend state changes
+ if (mUsingZeroColorMaskWorkaround)
+ {
+ mDirtyBits.set(DIRTY_BIT_COLOR_MASK);
+ }
+ }
+ break;
+ case gl::State::DIRTY_BIT_BLEND_FUNCS:
+ {
+ const gl::BlendState &blendState = state.getBlendState();
+ if (blendState.sourceBlendRGB != mCurBlendState.sourceBlendRGB ||
+ blendState.destBlendRGB != mCurBlendState.destBlendRGB ||
+ blendState.sourceBlendAlpha != mCurBlendState.sourceBlendAlpha ||
+ blendState.destBlendAlpha != mCurBlendState.destBlendAlpha)
+ {
+ mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS);
+ // BlendColor depends on the values of blend funcs
+ mDirtyBits.set(DIRTY_BIT_BLEND_COLOR);
+
+ // The color mask may have to be updated if the blend funcs change
+ if (mUsingZeroColorMaskWorkaround)
+ {
+ mDirtyBits.set(DIRTY_BIT_COLOR_MASK);
+ }
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_BLEND_EQUATIONS:
+ {
+ const gl::BlendState &blendState = state.getBlendState();
+ if (blendState.blendEquationRGB != mCurBlendState.blendEquationRGB ||
+ blendState.blendEquationAlpha != mCurBlendState.blendEquationAlpha)
+ {
+ mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS);
+
+ // The color mask may have to be updated if the blend funcs change
+ if (mUsingZeroColorMaskWorkaround)
+ {
+ mDirtyBits.set(DIRTY_BIT_COLOR_MASK);
+ }
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
+ if (state.getBlendState().sampleAlphaToCoverage !=
+ mCurBlendState.sampleAlphaToCoverage)
+ {
+ mDirtyBits.set(DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE);
+ }
+ break;
+ case gl::State::DIRTY_BIT_COLOR_MASK:
+ {
+ const gl::BlendState &blendState = state.getBlendState();
+ if (blendState.colorMaskRed != mCurBlendState.colorMaskRed ||
+ blendState.colorMaskGreen != mCurBlendState.colorMaskGreen ||
+ blendState.colorMaskBlue != mCurBlendState.colorMaskBlue ||
+ blendState.colorMaskAlpha != mCurBlendState.colorMaskAlpha)
+ {
+ mDirtyBits.set(DIRTY_BIT_COLOR_MASK);
+
+ // The color mask can cause the blend state to get out of sync when using the
+ // zero color mask workaround
+ if (mUsingZeroColorMaskWorkaround)
+ {
+ mDirtyBits.set(DIRTY_BIT_BLEND_ENABLED);
+ mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS);
+ }
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_DITHER_ENABLED:
+ if (state.getBlendState().dither != mCurBlendState.dither)
+ {
+ mDirtyBits.set(DIRTY_BIT_DITHER);
+ }
+ break;
+ case gl::State::DIRTY_BIT_BLEND_COLOR:
+ if (state.getBlendColor() != mCurBlendColor)
+ {
+ mDirtyBits.set(DIRTY_BIT_BLEND_COLOR);
+ }
+ break;
+ case gl::State::DIRTY_BIT_CULL_FACE_ENABLED:
+ if (state.getRasterizerState().cullFace != mCurRasterState.cullFace)
+ {
+ mDirtyBits.set(DIRTY_BIT_CULL_MODE);
+ }
+ break;
+ case gl::State::DIRTY_BIT_CULL_FACE:
+ if (state.getRasterizerState().cullMode != mCurRasterState.cullMode)
+ {
+ mDirtyBits.set(DIRTY_BIT_CULL_MODE);
+ }
+ break;
+ case gl::State::DIRTY_BIT_FRONT_FACE:
+ if (state.getRasterizerState().frontFace != mCurRasterState.frontFace)
+ {
+ mDirtyBits.set(DIRTY_BIT_CULL_MODE);
+
+ // Viewport state depends on rasterizer.frontface
+ mDirtyBits.set(DIRTY_BIT_VIEWPORT);
+ }
+ break;
+ case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED:
+ if (state.getRasterizerState().polygonOffsetFill !=
+ mCurRasterState.polygonOffsetFill)
+ {
+ mDirtyBits.set(DIRTY_BIT_DEPTH_BIAS);
+ }
+ break;
+ case gl::State::DIRTY_BIT_POLYGON_OFFSET:
+ {
+ const gl::RasterizerState &rasterizerState = state.getRasterizerState();
+ if (rasterizerState.polygonOffsetFactor != mCurRasterState.polygonOffsetFactor ||
+ rasterizerState.polygonOffsetUnits != mCurRasterState.polygonOffsetUnits)
+ {
+ mDirtyBits.set(DIRTY_BIT_DEPTH_BIAS);
+ }
+ }
+ case gl::State::DIRTY_BIT_DEPTH_MASK:
+ if (state.getDepthStencilState().depthMask != mCurDepthStencilState.depthMask)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_MASK);
+ }
+ break;
+ case gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED:
+ if (state.getDepthStencilState().depthTest != mCurDepthStencilState.depthTest)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_FUNC);
+ }
+ break;
+ case gl::State::DIRTY_BIT_DEPTH_FUNC:
+ if (state.getDepthStencilState().depthFunc != mCurDepthStencilState.depthFunc)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_FUNC);
+ }
+ break;
+ case gl::State::DIRTY_BIT_STENCIL_TEST_ENABLED:
+ if (state.getDepthStencilState().stencilTest != mCurDepthStencilState.stencilTest)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_TEST_ENABLED);
+ // If we enable the stencil test, all of these must be set
+ mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK);
+ mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
+ mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_FRONT);
+ mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_BACK);
+ mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_FRONT);
+ mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_BACK);
+ }
+ break;
+ case gl::State::DIRTY_BIT_STENCIL_FUNCS_FRONT:
+ {
+ const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
+ if (depthStencilState.stencilFunc != mCurDepthStencilState.stencilFunc ||
+ depthStencilState.stencilMask != mCurDepthStencilState.stencilMask ||
+ state.getStencilRef() != mCurStencilRef)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_FRONT);
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_STENCIL_FUNCS_BACK:
+ {
+ const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
+ if (depthStencilState.stencilBackFunc != mCurDepthStencilState.stencilBackFunc ||
+ depthStencilState.stencilBackMask != mCurDepthStencilState.stencilBackMask ||
+ state.getStencilBackRef() != mCurStencilBackRef)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_BACK);
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT:
+ if (state.getDepthStencilState().stencilWritemask !=
+ mCurDepthStencilState.stencilWritemask)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
+ }
+ break;
+ case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK:
+ if (state.getDepthStencilState().stencilBackWritemask !=
+ mCurDepthStencilState.stencilBackWritemask)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK);
+ }
+ break;
+ case gl::State::DIRTY_BIT_STENCIL_OPS_FRONT:
+ {
+ const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
+ if (depthStencilState.stencilFail != mCurDepthStencilState.stencilFail ||
+ depthStencilState.stencilPassDepthFail !=
+ mCurDepthStencilState.stencilPassDepthFail ||
+ depthStencilState.stencilPassDepthPass !=
+ mCurDepthStencilState.stencilPassDepthPass)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_FRONT);
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_STENCIL_OPS_BACK:
+ {
+ const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
+ if (depthStencilState.stencilBackFail != mCurDepthStencilState.stencilBackFail ||
+ depthStencilState.stencilBackPassDepthFail !=
+ mCurDepthStencilState.stencilBackPassDepthFail ||
+ depthStencilState.stencilBackPassDepthPass !=
+ mCurDepthStencilState.stencilBackPassDepthPass)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_BACK);
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_SCISSOR_TEST_ENABLED:
+ if (state.isScissorTestEnabled() != mCurScissorEnabled)
+ {
+ mDirtyBits.set(DIRTY_BIT_SCISSOR_ENABLED);
+ // If scissor is enabled, we have to set the scissor rect
+ mDirtyBits.set(DIRTY_BIT_SCISSOR_RECT);
+ }
+ break;
+ case gl::State::DIRTY_BIT_SCISSOR:
+ if (state.getScissor() != mCurScissorRect)
+ {
+ mDirtyBits.set(DIRTY_BIT_SCISSOR_RECT);
+ }
+ break;
+ case gl::State::DIRTY_BIT_DEPTH_RANGE:
+ if (state.getNearPlane() != mCurNear || state.getFarPlane() != mCurFar)
+ {
+ mDirtyBits.set(DIRTY_BIT_VIEWPORT);
+ }
+ break;
+ case gl::State::DIRTY_BIT_VIEWPORT:
+ if (state.getViewport() != mCurViewport)
+ {
+ mDirtyBits.set(DIRTY_BIT_VIEWPORT);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+gl::Error StateManager9::setBlendDepthRasterStates(const gl::State &glState,
+ unsigned int sampleMask)
+{
+ const gl::Framebuffer *framebuffer = glState.getDrawFramebuffer();
+
+ const gl::BlendState &blendState = glState.getBlendState();
+ const gl::ColorF &blendColor = glState.getBlendColor();
+ const gl::RasterizerState &rasterState = glState.getRasterizerState();
+
+ const auto &depthStencilState = glState.getDepthStencilState();
+ bool frontFaceCCW = (glState.getRasterizerState().frontFace == GL_CCW);
+ unsigned int maxStencil = (1 << mCurStencilSize) - 1;
+
+ // All the depth stencil states depends on the front face ccw variable
+ if (frontFaceCCW != mCurFrontFaceCCW)
+ {
+ forceSetDepthStencilState();
+ mCurFrontFaceCCW = frontFaceCCW;
+ }
+
+ for (auto dirtyBit : angle::IterateBitSet(mDirtyBits))
+ {
+ switch (dirtyBit)
+ {
+ case DIRTY_BIT_BLEND_ENABLED:
+ setBlendEnabled(blendState.blend);
+ break;
+ case DIRTY_BIT_BLEND_COLOR:
+ setBlendColor(blendState, blendColor);
+ break;
+ case DIRTY_BIT_BLEND_FUNCS_EQUATIONS:
+ setBlendFuncsEquations(blendState);
+ break;
+ case DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE:
+ setSampleAlphaToCoverage(blendState.sampleAlphaToCoverage);
+ break;
+ case DIRTY_BIT_COLOR_MASK:
+ setColorMask(framebuffer, blendState.colorMaskRed, blendState.colorMaskBlue,
+ blendState.colorMaskGreen, blendState.colorMaskAlpha);
+ break;
+ case DIRTY_BIT_DITHER:
+ setDither(blendState.dither);
+ break;
+ case DIRTY_BIT_CULL_MODE:
+ setCullMode(rasterState.cullFace, rasterState.cullMode, rasterState.frontFace);
+ break;
+ case DIRTY_BIT_DEPTH_BIAS:
+ setDepthBias(rasterState.polygonOffsetFill, rasterState.polygonOffsetFactor,
+ rasterState.polygonOffsetUnits);
+ break;
+ case DIRTY_BIT_STENCIL_DEPTH_MASK:
+ setDepthMask(depthStencilState.depthMask);
+ break;
+ case DIRTY_BIT_STENCIL_DEPTH_FUNC:
+ setDepthFunc(depthStencilState.depthTest, depthStencilState.depthFunc);
+ break;
+ case DIRTY_BIT_STENCIL_TEST_ENABLED:
+ setStencilTestEnabled(depthStencilState.stencilTest);
+ break;
+ case DIRTY_BIT_STENCIL_FUNCS_FRONT:
+ setStencilFuncsFront(depthStencilState.stencilFunc, depthStencilState.stencilMask,
+ glState.getStencilRef(), frontFaceCCW, maxStencil);
+ break;
+ case DIRTY_BIT_STENCIL_FUNCS_BACK:
+ setStencilFuncsBack(depthStencilState.stencilBackFunc,
+ depthStencilState.stencilBackMask, glState.getStencilBackRef(),
+ frontFaceCCW, maxStencil);
+ break;
+ case DIRTY_BIT_STENCIL_WRITEMASK_FRONT:
+ setStencilWriteMask(depthStencilState.stencilWritemask, frontFaceCCW);
+ break;
+ case DIRTY_BIT_STENCIL_WRITEMASK_BACK:
+ setStencilBackWriteMask(depthStencilState.stencilBackWritemask, frontFaceCCW);
+ break;
+ case DIRTY_BIT_STENCIL_OPS_FRONT:
+ setStencilOpsFront(depthStencilState.stencilFail,
+ depthStencilState.stencilPassDepthFail,
+ depthStencilState.stencilPassDepthPass, frontFaceCCW);
+ break;
+ case DIRTY_BIT_STENCIL_OPS_BACK:
+ setStencilOpsBack(depthStencilState.stencilBackFail,
+ depthStencilState.stencilBackPassDepthFail,
+ depthStencilState.stencilBackPassDepthPass, frontFaceCCW);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (sampleMask != mCurSampleMask)
+ {
+ setSampleMask(sampleMask);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+void StateManager9::setViewportState(const gl::Rectangle &viewport,
+ float zNear,
+ float zFar,
+ GLenum drawMode,
+ GLenum frontFace,
+ bool ignoreViewport)
+{
+ if (!mDirtyBits.test(DIRTY_BIT_VIEWPORT) && mCurIgnoreViewport == ignoreViewport)
+ return;
+
+ gl::Rectangle actualViewport = viewport;
+ float actualZNear = gl::clamp01(zNear);
+ float actualZFar = gl::clamp01(zFar);
+
+ if (ignoreViewport)
+ {
+ actualViewport.x = 0;
+ actualViewport.y = 0;
+ actualViewport.width = static_cast<int>(mRenderTargetBounds.width);
+ actualViewport.height = static_cast<int>(mRenderTargetBounds.height);
+ actualZNear = 0.0f;
+ actualZFar = 1.0f;
+ }
+
+ D3DVIEWPORT9 dxViewport;
+ dxViewport.X = gl::clamp(actualViewport.x, 0, static_cast<int>(mRenderTargetBounds.width));
+ dxViewport.Y = gl::clamp(actualViewport.y, 0, static_cast<int>(mRenderTargetBounds.height));
+ dxViewport.Width =
+ gl::clamp(actualViewport.width, 0,
+ static_cast<int>(mRenderTargetBounds.width) - static_cast<int>(dxViewport.X));
+ dxViewport.Height =
+ gl::clamp(actualViewport.height, 0,
+ static_cast<int>(mRenderTargetBounds.height) - static_cast<int>(dxViewport.Y));
+ dxViewport.MinZ = actualZNear;
+ dxViewport.MaxZ = actualZFar;
+
+ float depthFront = !gl::IsTriangleMode(drawMode) ? 0.0f : (frontFace == GL_CCW ? 1.0f : -1.0f);
+
+ mRenderer9->getDevice()->SetViewport(&dxViewport);
+
+ mCurViewport = actualViewport;
+ mCurNear = actualZNear;
+ mCurFar = actualZFar;
+ mCurDepthFront = depthFront;
+ mCurIgnoreViewport = ignoreViewport;
+
+ // Setting shader constants
+ dx_VertexConstants9 vc = {};
+ dx_PixelConstants9 pc = {};
+
+ vc.viewAdjust[0] =
+ static_cast<float>((actualViewport.width - static_cast<int>(dxViewport.Width)) +
+ 2 * (actualViewport.x - static_cast<int>(dxViewport.X)) - 1) /
+ dxViewport.Width;
+ vc.viewAdjust[1] =
+ static_cast<float>((actualViewport.height - static_cast<int>(dxViewport.Height)) +
+ 2 * (actualViewport.y - static_cast<int>(dxViewport.Y)) - 1) /
+ dxViewport.Height;
+ vc.viewAdjust[2] = static_cast<float>(actualViewport.width) / dxViewport.Width;
+ vc.viewAdjust[3] = static_cast<float>(actualViewport.height) / dxViewport.Height;
+
+ pc.viewCoords[0] = actualViewport.width * 0.5f;
+ pc.viewCoords[1] = actualViewport.height * 0.5f;
+ pc.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f);
+ pc.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f);
+
+ pc.depthFront[0] = (actualZFar - actualZNear) * 0.5f;
+ pc.depthFront[1] = (actualZNear + actualZFar) * 0.5f;
+ pc.depthFront[2] = depthFront;
+
+ vc.depthRange[0] = actualZNear;
+ vc.depthRange[1] = actualZFar;
+ vc.depthRange[2] = actualZFar - actualZNear;
+
+ pc.depthRange[0] = actualZNear;
+ pc.depthRange[1] = actualZFar;
+ pc.depthRange[2] = actualZFar - actualZNear;
+
+ if (memcmp(&vc, &mVertexConstants, sizeof(dx_VertexConstants9)) != 0)
+ {
+ mVertexConstants = vc;
+ mDxUniformsDirty = true;
+ }
+
+ if (memcmp(&pc, &mPixelConstants, sizeof(dx_PixelConstants9)) != 0)
+ {
+ mPixelConstants = pc;
+ mDxUniformsDirty = true;
+ }
+
+ mForceSetViewport = false;
+}
+
+void StateManager9::setShaderConstants()
+{
+ if (!mDxUniformsDirty)
+ return;
+
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ device->SetVertexShaderConstantF(0, reinterpret_cast<float *>(&mVertexConstants),
+ sizeof(dx_VertexConstants9) / sizeof(float[4]));
+ device->SetPixelShaderConstantF(0, reinterpret_cast<float *>(&mPixelConstants),
+ sizeof(dx_PixelConstants9) / sizeof(float[4]));
+ mDxUniformsDirty = false;
+}
+
+// This is separate from the main state loop because other functions
+// outside call only setScissorState to update scissor state
+void StateManager9::setScissorState(const gl::Rectangle &scissor, bool enabled)
+{
+ if (mDirtyBits.test(DIRTY_BIT_SCISSOR_ENABLED))
+ setScissorEnabled(enabled);
+
+ if (mDirtyBits.test(DIRTY_BIT_SCISSOR_RECT))
+ setScissorRect(scissor, enabled);
+}
+
+void StateManager9::setRenderTargetBounds(size_t width, size_t height)
+{
+ mRenderTargetBounds.width = (int)width;
+ mRenderTargetBounds.height = (int)height;
+ forceSetViewportState();
+}
+
+void StateManager9::setScissorEnabled(bool scissorEnabled)
+{
+ mRenderer9->getDevice()->SetRenderState(D3DRS_SCISSORTESTENABLE, scissorEnabled ? TRUE : FALSE);
+ mCurScissorEnabled = scissorEnabled;
+}
+
+void StateManager9::setScissorRect(const gl::Rectangle &scissor, bool enabled)
+{
+ if (!enabled)
+ return;
+
+ RECT rect;
+ rect.left = gl::clamp(scissor.x, 0, static_cast<int>(mRenderTargetBounds.width));
+ rect.top = gl::clamp(scissor.y, 0, static_cast<int>(mRenderTargetBounds.height));
+ rect.right =
+ gl::clamp(scissor.x + scissor.width, 0, static_cast<int>(mRenderTargetBounds.width));
+ rect.bottom =
+ gl::clamp(scissor.y + scissor.height, 0, static_cast<int>(mRenderTargetBounds.height));
+ mRenderer9->getDevice()->SetScissorRect(&rect);
+}
+
+void StateManager9::setDepthFunc(bool depthTest, GLenum depthFunc)
+{
+ if (depthTest)
+ {
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
+ device->SetRenderState(D3DRS_ZFUNC, gl_d3d9::ConvertComparison(depthFunc));
+ }
+ else
+ {
+ mRenderer9->getDevice()->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
+ }
+
+ mCurDepthStencilState.depthTest = depthTest;
+ mCurDepthStencilState.depthFunc = depthFunc;
+}
+
+void StateManager9::setStencilOpsFront(GLenum stencilFail,
+ GLenum stencilPassDepthFail,
+ GLenum stencilPassDepthPass,
+ bool frontFaceCCW)
+{
+ // TODO(dianx) It may be slightly more efficient todo these and other similar areas
+ // with separate dirty bits.
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ device->SetRenderState(frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
+ gl_d3d9::ConvertStencilOp(stencilFail));
+ device->SetRenderState(frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
+ gl_d3d9::ConvertStencilOp(stencilPassDepthFail));
+ device->SetRenderState(frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
+ gl_d3d9::ConvertStencilOp(stencilPassDepthPass));
+
+ mCurDepthStencilState.stencilFail = stencilFail;
+ mCurDepthStencilState.stencilPassDepthFail = stencilPassDepthFail;
+ mCurDepthStencilState.stencilPassDepthPass = stencilPassDepthPass;
+}
+
+void StateManager9::setStencilOpsBack(GLenum stencilBackFail,
+ GLenum stencilBackPassDepthFail,
+ GLenum stencilBackPassDepthPass,
+ bool frontFaceCCW)
+{
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
+ gl_d3d9::ConvertStencilOp(stencilBackFail));
+ device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
+ gl_d3d9::ConvertStencilOp(stencilBackPassDepthFail));
+ device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
+ gl_d3d9::ConvertStencilOp(stencilBackPassDepthPass));
+
+ mCurDepthStencilState.stencilBackFail = stencilBackFail;
+ mCurDepthStencilState.stencilBackPassDepthFail = stencilBackPassDepthFail;
+ mCurDepthStencilState.stencilBackPassDepthPass = stencilBackPassDepthPass;
+}
+
+void StateManager9::setStencilBackWriteMask(GLuint stencilBackWriteMask, bool frontFaceCCW)
+{
+ mRenderer9->getDevice()->SetRenderState(
+ !frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, stencilBackWriteMask);
+
+ mCurDepthStencilState.stencilBackWritemask = stencilBackWriteMask;
+}
+
+void StateManager9::setStencilFuncsBack(GLenum stencilBackFunc,
+ GLuint stencilBackMask,
+ GLint stencilBackRef,
+ bool frontFaceCCW,
+ unsigned int maxStencil)
+{
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
+ gl_d3d9::ConvertComparison(stencilBackFunc));
+ device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF,
+ (stencilBackRef < (int)maxStencil) ? stencilBackRef : maxStencil);
+ device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK,
+ stencilBackMask);
+
+ mCurDepthStencilState.stencilBackFunc = stencilBackFunc;
+ mCurStencilBackRef = stencilBackRef;
+ mCurDepthStencilState.stencilBackMask = stencilBackMask;
+}
+
+void StateManager9::setStencilWriteMask(GLuint stencilWriteMask, bool frontFaceCCW)
+{
+ mRenderer9->getDevice()->SetRenderState(
+ frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, stencilWriteMask);
+ mCurDepthStencilState.stencilWritemask = stencilWriteMask;
+}
+
+void StateManager9::setStencilFuncsFront(GLenum stencilFunc,
+ GLuint stencilMask,
+ GLint stencilRef,
+ bool frontFaceCCW,
+ unsigned int maxStencil)
+{
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ device->SetRenderState(frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
+ gl_d3d9::ConvertComparison(stencilFunc));
+ device->SetRenderState(frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF,
+ (stencilRef < static_cast<int>(maxStencil)) ? stencilRef : maxStencil);
+ device->SetRenderState(frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, stencilMask);
+
+ mCurDepthStencilState.stencilFunc = stencilFunc;
+ mCurStencilRef = stencilRef;
+ mCurDepthStencilState.stencilMask = stencilMask;
+}
+void StateManager9::setStencilTestEnabled(bool stencilTestEnabled)
+{
+ if (stencilTestEnabled && mCurStencilSize > 0)
+ {
+ mRenderer9->getDevice()->SetRenderState(D3DRS_STENCILENABLE, TRUE);
+ mRenderer9->getDevice()->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
+ }
+ else
+ {
+ mRenderer9->getDevice()->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+ }
+
+ mCurDepthStencilState.stencilTest = stencilTestEnabled;
+}
+
+void StateManager9::setDepthMask(bool depthMask)
+{
+ mRenderer9->getDevice()->SetRenderState(D3DRS_ZWRITEENABLE, depthMask ? TRUE : FALSE);
+ mCurDepthStencilState.depthMask = depthMask;
+}
+
+// TODO(dianx) one bit for sampleAlphaToCoverage
+void StateManager9::setSampleAlphaToCoverage(bool enabled)
+{
+ if (enabled)
+ {
+ FIXME("Sample alpha to coverage is unimplemented.");
+ }
+}
+
+void StateManager9::setBlendColor(const gl::BlendState &blendState, const gl::ColorF &blendColor)
+{
+ if (!blendState.blend)
+ return;
+
+ if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA &&
+ blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA &&
+ blendState.destBlendRGB != GL_CONSTANT_ALPHA &&
+ blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA)
+ {
+ mRenderer9->getDevice()->SetRenderState(D3DRS_BLENDFACTOR,
+ gl_d3d9::ConvertColor(blendColor));
+ }
+ else
+ {
+ mRenderer9->getDevice()->SetRenderState(
+ D3DRS_BLENDFACTOR,
+ D3DCOLOR_RGBA(gl::unorm<8>(blendColor.alpha), gl::unorm<8>(blendColor.alpha),
+ gl::unorm<8>(blendColor.alpha), gl::unorm<8>(blendColor.alpha)));
+ }
+ mCurBlendColor = blendColor;
+}
+
+void StateManager9::setBlendFuncsEquations(const gl::BlendState &blendState)
+{
+ if (!blendState.blend)
+ return;
+
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+
+ device->SetRenderState(D3DRS_SRCBLEND, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendRGB));
+ device->SetRenderState(D3DRS_DESTBLEND, gl_d3d9::ConvertBlendFunc(blendState.destBlendRGB));
+ device->SetRenderState(D3DRS_BLENDOP, gl_d3d9::ConvertBlendOp(blendState.blendEquationRGB));
+
+ if (blendState.sourceBlendRGB != blendState.sourceBlendAlpha ||
+ blendState.destBlendRGB != blendState.destBlendAlpha ||
+ blendState.blendEquationRGB != blendState.blendEquationAlpha)
+ {
+ device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+
+ device->SetRenderState(D3DRS_SRCBLENDALPHA,
+ gl_d3d9::ConvertBlendFunc(blendState.sourceBlendAlpha));
+ device->SetRenderState(D3DRS_DESTBLENDALPHA,
+ gl_d3d9::ConvertBlendFunc(blendState.destBlendAlpha));
+ device->SetRenderState(D3DRS_BLENDOPALPHA,
+ gl_d3d9::ConvertBlendOp(blendState.blendEquationAlpha));
+ }
+ else
+ {
+ device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
+ }
+
+ mCurBlendState.sourceBlendRGB = blendState.sourceBlendRGB;
+ mCurBlendState.destBlendRGB = blendState.destBlendRGB;
+ mCurBlendState.blendEquationRGB = blendState.blendEquationRGB;
+ mCurBlendState.blendEquationAlpha = blendState.blendEquationAlpha;
+}
+
+void StateManager9::setBlendEnabled(bool enabled)
+{
+ mRenderer9->getDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE, enabled ? TRUE : FALSE);
+ mCurBlendState.blend = enabled;
+}
+
+void StateManager9::setDither(bool dither)
+{
+ mRenderer9->getDevice()->SetRenderState(D3DRS_DITHERENABLE, dither ? TRUE : FALSE);
+ mCurBlendState.dither = dither;
+}
+
+// TODO(dianx) one bit for color mask
+void StateManager9::setColorMask(const gl::Framebuffer *framebuffer,
+ bool red,
+ bool blue,
+ bool green,
+ bool alpha)
+{
+ // Set the color mask
+
+ const auto *attachment = framebuffer->getFirstColorbuffer();
+ const auto &format = attachment ? attachment->getFormat() : gl::Format::Invalid();
+
+ DWORD colorMask = gl_d3d9::ConvertColorMask(
+ format.info->redBits > 0 && red, format.info->greenBits > 0 && green,
+ format.info->blueBits > 0 && blue, format.info->alphaBits > 0 && alpha);
+
+ // Apparently some ATI cards have a bug where a draw with a zero color write mask can cause
+ // later draws to have incorrect results. Instead, set a nonzero color write mask but modify the
+ // blend state so that no drawing is done.
+ // http://anglebug.com/169
+ if (colorMask == 0 && mUsingZeroColorMaskWorkaround)
+ {
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ // Enable green channel, but set blending so nothing will be drawn.
+ device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN);
+
+ device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+
+ device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
+ device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
+ device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
+
+ mCurBlendState.colorMaskRed = false;
+ mCurBlendState.colorMaskGreen = true;
+ mCurBlendState.colorMaskBlue = false;
+ mCurBlendState.colorMaskAlpha = false;
+
+ mCurBlendState.blend = true;
+ mCurBlendState.sourceBlendRGB = GL_ZERO;
+ mCurBlendState.sourceBlendAlpha = GL_ZERO;
+ mCurBlendState.destBlendRGB = GL_ONE;
+ mCurBlendState.destBlendAlpha = GL_ONE;
+ mCurBlendState.blendEquationRGB = GL_FUNC_ADD;
+ mCurBlendState.blendEquationAlpha = GL_FUNC_ADD;
+ }
+ else
+ {
+ mRenderer9->getDevice()->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask);
+
+ mCurBlendState.colorMaskRed = red;
+ mCurBlendState.colorMaskGreen = green;
+ mCurBlendState.colorMaskBlue = blue;
+ mCurBlendState.colorMaskAlpha = alpha;
+ }
+}
+
+void StateManager9::setSampleMask(unsigned int sampleMask)
+{
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ // Set the multisample mask
+ device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
+ device->SetRenderState(D3DRS_MULTISAMPLEMASK, static_cast<DWORD>(sampleMask));
+
+ mCurSampleMask = sampleMask;
+}
+
+void StateManager9::setCullMode(bool cullFace, GLenum cullMode, GLenum frontFace)
+{
+ if (cullFace)
+ {
+ mRenderer9->getDevice()->SetRenderState(D3DRS_CULLMODE,
+ gl_d3d9::ConvertCullMode(cullMode, frontFace));
+ }
+ else
+ {
+ mRenderer9->getDevice()->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ }
+
+ mCurRasterState.cullFace = cullFace;
+ mCurRasterState.cullMode = cullMode;
+ mCurRasterState.frontFace = frontFace;
+}
+
+void StateManager9::setDepthBias(bool polygonOffsetFill,
+ GLfloat polygonOffsetFactor,
+ GLfloat polygonOffsetUnits)
+{
+ if (polygonOffsetFill)
+ {
+ if (mCurDepthSize > 0)
+ {
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD *)&polygonOffsetFactor);
+
+ float depthBias = ldexp(polygonOffsetUnits, -static_cast<int>(mCurDepthSize));
+ device->SetRenderState(D3DRS_DEPTHBIAS, *(DWORD *)&depthBias);
+ }
+ }
+ else
+ {
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0);
+ device->SetRenderState(D3DRS_DEPTHBIAS, 0);
+ }
+
+ mCurRasterState.polygonOffsetFill = polygonOffsetFill;
+ mCurRasterState.polygonOffsetFactor = polygonOffsetFactor;
+ mCurRasterState.polygonOffsetUnits = polygonOffsetUnits;
+}
+
+void StateManager9::updateDepthSizeIfChanged(bool depthStencilInitialized, unsigned int depthSize)
+{
+ if (!depthStencilInitialized || depthSize != mCurDepthSize)
+ {
+ mCurDepthSize = depthSize;
+ forceSetRasterState();
+ }
+}
+} // namespace rx
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h
new file mode 100755
index 000000000..bd2cef2e5
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h
@@ -0,0 +1,209 @@
+//
+// Copyright (c) 2015 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.
+//
+
+// StateManager9.h: Defines a class for caching D3D9 state
+
+#ifndef LIBANGLE_RENDERER_D3D9_STATEMANAGER9_H_
+#define LIBANGLE_RENDERER_D3D9_STATEMANAGER9_H_
+
+#include "libANGLE/angletypes.h"
+#include "libANGLE/ContextState.h"
+#include "libANGLE/State.h"
+#include "libANGLE/renderer/d3d/RendererD3D.h"
+
+namespace rx
+{
+
+class Renderer9;
+
+struct dx_VertexConstants9
+{
+ float depthRange[4];
+ float viewAdjust[4];
+ float viewCoords[4];
+};
+
+struct dx_PixelConstants9
+{
+ float depthRange[4];
+ float viewCoords[4];
+ float depthFront[4];
+};
+
+class StateManager9 final : angle::NonCopyable
+{
+ public:
+ StateManager9(Renderer9 *renderer9);
+ ~StateManager9();
+
+ void initialize();
+
+ void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits);
+
+ gl::Error setBlendDepthRasterStates(const gl::State &glState, unsigned int sampleMask);
+ void setScissorState(const gl::Rectangle &scissor, bool enabled);
+ void setViewportState(const gl::Rectangle &viewport,
+ float zNear,
+ float zFar,
+ GLenum drawMode,
+ GLenum frontFace,
+ bool ignoreViewport);
+
+ void setShaderConstants();
+
+ void forceSetBlendState();
+ void forceSetRasterState();
+ void forceSetDepthStencilState();
+ void forceSetScissorState();
+ void forceSetViewportState();
+ void forceSetDXUniformsState();
+
+ void updateDepthSizeIfChanged(bool depthStencilInitialized, unsigned int depthSize);
+ void updateStencilSizeIfChanged(bool depthStencilInitialized, unsigned int stencilSize);
+
+ void setRenderTargetBounds(size_t width, size_t height);
+
+ int getRenderTargetWidth() const { return mRenderTargetBounds.width; }
+ int getRenderTargetHeight() const { return mRenderTargetBounds.height; }
+
+ void resetDirtyBits() { mDirtyBits.reset(); }
+
+ private:
+ // Blend state functions
+ void setBlendEnabled(bool enabled);
+ void setBlendColor(const gl::BlendState &blendState, const gl::ColorF &blendColor);
+ void setBlendFuncsEquations(const gl::BlendState &blendState);
+ void setColorMask(const gl::Framebuffer *framebuffer,
+ bool red,
+ bool blue,
+ bool green,
+ bool alpha);
+ void setSampleAlphaToCoverage(bool enabled);
+ void setDither(bool dither);
+ void setSampleMask(unsigned int sampleMask);
+
+ // Current raster state functions
+ void setCullMode(bool cullFace, GLenum cullMode, GLenum frontFace);
+ void setDepthBias(bool polygonOffsetFill,
+ GLfloat polygonOffsetFactor,
+ GLfloat polygonOffsetUnits);
+
+ // Depth stencil state functions
+ void setStencilOpsFront(GLenum stencilFail,
+ GLenum stencilPassDepthFail,
+ GLenum stencilPassDepthPass,
+ bool frontFaceCCW);
+ void setStencilOpsBack(GLenum stencilBackFail,
+ GLenum stencilBackPassDepthFail,
+ GLenum stencilBackPassDepthPass,
+ bool frontFaceCCW);
+ void setStencilBackWriteMask(GLuint stencilBackWriteMask, bool frontFaceCCW);
+ void setDepthFunc(bool depthTest, GLenum depthFunc);
+ void setStencilTestEnabled(bool enabled);
+ void setDepthMask(bool depthMask);
+ void setStencilFuncsFront(GLenum stencilFunc,
+ GLuint stencilMask,
+ GLint stencilRef,
+ bool frontFaceCCW,
+ unsigned int maxStencil);
+ void setStencilFuncsBack(GLenum stencilBackFunc,
+ GLuint stencilBackMask,
+ GLint stencilBackRef,
+ bool frontFaceCCW,
+ unsigned int maxStencil);
+ void setStencilWriteMask(GLuint stencilWriteMask, bool frontFaceCCW);
+
+ void setScissorEnabled(bool scissorEnabled);
+ void setScissorRect(const gl::Rectangle &scissor, bool enabled);
+
+ enum DirtyBitType
+ {
+ // Blend dirty bits
+ DIRTY_BIT_BLEND_ENABLED,
+ DIRTY_BIT_BLEND_COLOR,
+ DIRTY_BIT_BLEND_FUNCS_EQUATIONS,
+ DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE,
+ DIRTY_BIT_COLOR_MASK,
+ DIRTY_BIT_DITHER,
+ DIRTY_BIT_SAMPLE_MASK,
+
+ // Rasterizer dirty bits
+ DIRTY_BIT_CULL_MODE,
+ DIRTY_BIT_DEPTH_BIAS,
+
+ // Depth stencil dirty bits
+ DIRTY_BIT_STENCIL_DEPTH_MASK,
+ DIRTY_BIT_STENCIL_DEPTH_FUNC,
+ DIRTY_BIT_STENCIL_TEST_ENABLED,
+ DIRTY_BIT_STENCIL_FUNCS_FRONT,
+ DIRTY_BIT_STENCIL_FUNCS_BACK,
+ DIRTY_BIT_STENCIL_WRITEMASK_FRONT,
+ DIRTY_BIT_STENCIL_WRITEMASK_BACK,
+ DIRTY_BIT_STENCIL_OPS_FRONT,
+ DIRTY_BIT_STENCIL_OPS_BACK,
+
+ // Scissor dirty bits
+ DIRTY_BIT_SCISSOR_ENABLED,
+ DIRTY_BIT_SCISSOR_RECT,
+
+ // Viewport dirty bits
+ DIRTY_BIT_VIEWPORT,
+
+ DIRTY_BIT_MAX
+ };
+
+ typedef std::bitset<DIRTY_BIT_MAX> DirtyBits;
+
+ bool mUsingZeroColorMaskWorkaround;
+
+ // Currently applied blend state
+ gl::BlendState mCurBlendState;
+ gl::ColorF mCurBlendColor;
+ unsigned int mCurSampleMask;
+ DirtyBits mBlendStateDirtyBits;
+
+ // Currently applied raster state
+ gl::RasterizerState mCurRasterState;
+ unsigned int mCurDepthSize;
+ DirtyBits mRasterizerStateDirtyBits;
+
+ // Currently applied depth stencil state
+ gl::DepthStencilState mCurDepthStencilState;
+ int mCurStencilRef;
+ int mCurStencilBackRef;
+ bool mCurFrontFaceCCW;
+ unsigned int mCurStencilSize;
+ DirtyBits mDepthStencilStateDirtyBits;
+
+ // Currently applied scissor states
+ gl::Rectangle mCurScissorRect;
+ bool mCurScissorEnabled;
+ gl::Extents mRenderTargetBounds;
+ DirtyBits mScissorStateDirtyBits;
+
+ // Currently applied viewport states
+ bool mForceSetViewport;
+ gl::Rectangle mCurViewport;
+ float mCurNear;
+ float mCurFar;
+ float mCurDepthFront;
+ bool mCurIgnoreViewport;
+
+ dx_VertexConstants9 mVertexConstants;
+ dx_PixelConstants9 mPixelConstants;
+ bool mDxUniformsDirty;
+
+ // FIXME: Unsupported by D3D9
+ static const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF;
+ static const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK;
+ static const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK;
+
+ Renderer9 *mRenderer9;
+ DirtyBits mDirtyBits;
+};
+
+} // namespace rx
+#endif // LIBANGLE_RENDERER_D3D9_STATEMANAGER9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp
new file mode 100755
index 000000000..7e6948ebb
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp
@@ -0,0 +1,442 @@
+//
+// Copyright (c) 2012-2014 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.
+//
+
+// SwapChain9.cpp: Implements a back-end specific class for the D3D9 swap chain.
+
+#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h"
+#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
+#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
+#include "libANGLE/renderer/d3d/d3d9/NativeWindow9.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+#include "libANGLE/features.h"
+
+namespace rx
+{
+
+SwapChain9::SwapChain9(Renderer9 *renderer,
+ NativeWindow9 *nativeWindow,
+ HANDLE shareHandle,
+ IUnknown *d3dTexture,
+ GLenum backBufferFormat,
+ GLenum depthBufferFormat,
+ EGLint orientation)
+ : SwapChainD3D(shareHandle, d3dTexture, backBufferFormat, depthBufferFormat),
+ mRenderer(renderer),
+ mWidth(-1),
+ mHeight(-1),
+ mSwapInterval(-1),
+ mNativeWindow(nativeWindow),
+ mSwapChain(nullptr),
+ mBackBuffer(nullptr),
+ mRenderTarget(nullptr),
+ mDepthStencil(nullptr),
+ mOffscreenTexture(nullptr),
+ mColorRenderTarget(this, false),
+ mDepthStencilRenderTarget(this, true)
+{
+ ASSERT(orientation == 0);
+}
+
+SwapChain9::~SwapChain9()
+{
+ release();
+}
+
+void SwapChain9::release()
+{
+ SafeRelease(mSwapChain);
+ SafeRelease(mBackBuffer);
+ SafeRelease(mDepthStencil);
+ SafeRelease(mRenderTarget);
+ SafeRelease(mOffscreenTexture);
+
+ if (mNativeWindow->getNativeWindow())
+ {
+ mShareHandle = NULL;
+ }
+}
+
+static DWORD convertInterval(EGLint interval)
+{
+#if ANGLE_VSYNC == ANGLE_DISABLED
+ return D3DPRESENT_INTERVAL_IMMEDIATE;
+#else
+ switch(interval)
+ {
+ case 0: return D3DPRESENT_INTERVAL_IMMEDIATE;
+ case 1: return D3DPRESENT_INTERVAL_ONE;
+ case 2: return D3DPRESENT_INTERVAL_TWO;
+ case 3: return D3DPRESENT_INTERVAL_THREE;
+ case 4: return D3DPRESENT_INTERVAL_FOUR;
+ default: UNREACHABLE();
+ }
+
+ return D3DPRESENT_INTERVAL_DEFAULT;
+#endif
+}
+
+EGLint SwapChain9::resize(int backbufferWidth, int backbufferHeight)
+{
+ // D3D9 does not support resizing swap chains without recreating them
+ return reset(backbufferWidth, backbufferHeight, mSwapInterval);
+}
+
+EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval)
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ if (device == NULL)
+ {
+ return EGL_BAD_ACCESS;
+ }
+
+ // Evict all non-render target textures to system memory and release all resources
+ // before reallocating them to free up as much video memory as possible.
+ device->EvictManagedResources();
+
+ HRESULT result;
+
+ // Release specific resources to free up memory for the new render target, while the
+ // old render target still exists for the purpose of preserving its contents.
+ SafeRelease(mSwapChain);
+ SafeRelease(mBackBuffer);
+ SafeRelease(mOffscreenTexture);
+ SafeRelease(mDepthStencil);
+
+ const d3d9::TextureFormat &backBufferd3dFormatInfo =
+ d3d9::GetTextureFormatInfo(mOffscreenRenderTargetFormat);
+ if (mD3DTexture != nullptr)
+ {
+ result = mD3DTexture->QueryInterface(&mOffscreenTexture);
+ ASSERT(SUCCEEDED(result));
+ }
+ else
+ {
+ HANDLE *pShareHandle = NULL;
+ if (!mNativeWindow->getNativeWindow() && mRenderer->getShareHandleSupport())
+ {
+ pShareHandle = &mShareHandle;
+ }
+
+ result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET,
+ backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT,
+ &mOffscreenTexture, pShareHandle);
+ if (FAILED(result))
+ {
+ ERR("Could not create offscreen texture: %08lX", result);
+ release();
+
+ if (d3d9::isDeviceLostError(result))
+ {
+ return EGL_CONTEXT_LOST;
+ }
+ else
+ {
+ return EGL_BAD_ALLOC;
+ }
+ }
+ }
+
+ IDirect3DSurface9 *oldRenderTarget = mRenderTarget;
+
+ result = mOffscreenTexture->GetSurfaceLevel(0, &mRenderTarget);
+ ASSERT(SUCCEEDED(result));
+
+ if (oldRenderTarget)
+ {
+ RECT rect =
+ {
+ 0, 0,
+ mWidth, mHeight
+ };
+
+ if (rect.right > static_cast<LONG>(backbufferWidth))
+ {
+ rect.right = backbufferWidth;
+ }
+
+ if (rect.bottom > static_cast<LONG>(backbufferHeight))
+ {
+ rect.bottom = backbufferHeight;
+ }
+
+ mRenderer->endScene();
+
+ result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE);
+ ASSERT(SUCCEEDED(result));
+
+ SafeRelease(oldRenderTarget);
+ }
+
+ const d3d9::TextureFormat &depthBufferd3dFormatInfo = d3d9::GetTextureFormatInfo(mDepthBufferFormat);
+
+ // Don't create a swapchain for NULLREF devices
+ D3DDEVTYPE deviceType = mRenderer->getD3D9DeviceType();
+ EGLNativeWindowType window = mNativeWindow->getNativeWindow();
+ if (window && deviceType != D3DDEVTYPE_NULLREF)
+ {
+ D3DPRESENT_PARAMETERS presentParameters = {0};
+ presentParameters.AutoDepthStencilFormat = depthBufferd3dFormatInfo.renderFormat;
+ presentParameters.BackBufferCount = 1;
+ presentParameters.BackBufferFormat = backBufferd3dFormatInfo.renderFormat;
+ presentParameters.EnableAutoDepthStencil = FALSE;
+ presentParameters.Flags = 0;
+ presentParameters.hDeviceWindow = window;
+ presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented
+ presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented
+ presentParameters.PresentationInterval = convertInterval(swapInterval);
+ presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ presentParameters.Windowed = TRUE;
+ presentParameters.BackBufferWidth = backbufferWidth;
+ presentParameters.BackBufferHeight = backbufferHeight;
+
+ // http://crbug.com/140239
+ // http://crbug.com/143434
+ //
+ // Some AMD/Intel switchable systems / drivers appear to round swap chain surfaces to a multiple of 64 pixels in width
+ // when using the integrated Intel. This rounds the width up rather than down.
+ //
+ // Some non-switchable AMD GPUs / drivers do not respect the source rectangle to Present. Therefore, when the vendor ID
+ // is not Intel, the back buffer width must be exactly the same width as the window or horizontal scaling will occur.
+ if (IsIntel(mRenderer->getVendorId()))
+ {
+ presentParameters.BackBufferWidth = (presentParameters.BackBufferWidth + 63) / 64 * 64;
+ }
+
+ result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST);
+
+ ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result);
+ release();
+
+ if (d3d9::isDeviceLostError(result))
+ {
+ return EGL_CONTEXT_LOST;
+ }
+ else
+ {
+ return EGL_BAD_ALLOC;
+ }
+ }
+
+ result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
+ ASSERT(SUCCEEDED(result));
+ InvalidateRect(window, NULL, FALSE);
+ }
+
+ if (mDepthBufferFormat != GL_NONE)
+ {
+ result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight,
+ depthBufferd3dFormatInfo.renderFormat,
+ D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL);
+
+ ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result);
+ release();
+
+ if (d3d9::isDeviceLostError(result))
+ {
+ return EGL_CONTEXT_LOST;
+ }
+ else
+ {
+ return EGL_BAD_ALLOC;
+ }
+ }
+ }
+
+ mWidth = backbufferWidth;
+ mHeight = backbufferHeight;
+ mSwapInterval = swapInterval;
+
+ return EGL_SUCCESS;
+}
+
+// parameters should be validated/clamped by caller
+EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
+{
+ if (!mSwapChain)
+ {
+ return EGL_SUCCESS;
+ }
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ // Disable all pipeline operations
+ device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
+ 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_STENCILENABLE, FALSE);
+ 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->SetPixelShader(NULL);
+ device->SetVertexShader(NULL);
+
+ device->SetRenderTarget(0, mBackBuffer);
+ device->SetDepthStencilSurface(NULL);
+
+ device->SetTexture(0, mOffscreenTexture);
+ device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+ device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
+ device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
+ device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
+ device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+ device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+ device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
+
+ for (UINT streamIndex = 0; streamIndex < gl::MAX_VERTEX_ATTRIBS; streamIndex++)
+ {
+ device->SetStreamSourceFreq(streamIndex, 1);
+ }
+
+ D3DVIEWPORT9 viewport = {0, 0, static_cast<DWORD>(mWidth), static_cast<DWORD>(mHeight), 0.0f, 1.0f};
+ device->SetViewport(&viewport);
+
+ float x1 = x - 0.5f;
+ float y1 = (mHeight - y - height) - 0.5f;
+ float x2 = (x + width) - 0.5f;
+ float y2 = (mHeight - y) - 0.5f;
+
+ float u1 = x / float(mWidth);
+ float v1 = y / float(mHeight);
+ float u2 = (x + width) / float(mWidth);
+ float v2 = (y + height) / float(mHeight);
+
+ float quad[4][6] = {{x1, y1, 0.0f, 1.0f, u1, v2},
+ {x2, y1, 0.0f, 1.0f, u2, v2},
+ {x2, y2, 0.0f, 1.0f, u2, v1},
+ {x1, y2, 0.0f, 1.0f, u1, v1}}; // x, y, z, rhw, u, v
+
+ mRenderer->startScene();
+ device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float));
+ mRenderer->endScene();
+
+ device->SetTexture(0, NULL);
+
+ RECT rect =
+ {
+ static_cast<LONG>(x), static_cast<LONG>(mHeight - y - height),
+ static_cast<LONG>(x + width), static_cast<LONG>(mHeight - y)
+ };
+
+ HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0);
+
+ mRenderer->markAllStateDirty();
+
+ if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR)
+ {
+ return EGL_BAD_ALLOC;
+ }
+
+ // On Windows 8 systems, IDirect3DSwapChain9::Present sometimes returns 0x88760873 when the windows is
+ // in the process of entering/exiting fullscreen. This code doesn't seem to have any documentation. The
+ // device appears to be ok after emitting this error so simply return a failure to swap.
+ if (result == static_cast<HRESULT>(0x88760873))
+ {
+ return EGL_BAD_MATCH;
+ }
+
+ // http://crbug.com/313210
+ // If our swap failed, trigger a device lost event. Resetting will work around an AMD-specific
+ // device removed bug with lost contexts when reinstalling drivers.
+ if (FAILED(result))
+ {
+ mRenderer->notifyDeviceLost();
+ return EGL_CONTEXT_LOST;
+ }
+
+ return EGL_SUCCESS;
+}
+
+// Increments refcount on surface.
+// caller must Release() the returned surface
+// TODO: remove the AddRef to match SwapChain11
+IDirect3DSurface9 *SwapChain9::getRenderTarget()
+{
+ if (mRenderTarget)
+ {
+ mRenderTarget->AddRef();
+ }
+
+ return mRenderTarget;
+}
+
+// Increments refcount on surface.
+// caller must Release() the returned surface
+// TODO: remove the AddRef to match SwapChain11
+IDirect3DSurface9 *SwapChain9::getDepthStencil()
+{
+ if (mDepthStencil)
+ {
+ mDepthStencil->AddRef();
+ }
+
+ return mDepthStencil;
+}
+
+// Increments refcount on texture.
+// caller must Release() the returned texture
+// TODO: remove the AddRef to match SwapChain11
+IDirect3DTexture9 *SwapChain9::getOffscreenTexture()
+{
+ if (mOffscreenTexture)
+ {
+ mOffscreenTexture->AddRef();
+ }
+
+ return mOffscreenTexture;
+}
+
+void *SwapChain9::getKeyedMutex()
+{
+ UNREACHABLE();
+ return nullptr;
+}
+
+void SwapChain9::recreate()
+{
+ if (!mSwapChain)
+ {
+ return;
+ }
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+ if (device == NULL)
+ {
+ return;
+ }
+
+ D3DPRESENT_PARAMETERS presentParameters;
+ HRESULT result = mSwapChain->GetPresentParameters(&presentParameters);
+ ASSERT(SUCCEEDED(result));
+
+ IDirect3DSwapChain9* newSwapChain = NULL;
+ result = device->CreateAdditionalSwapChain(&presentParameters, &newSwapChain);
+ if (FAILED(result))
+ {
+ return;
+ }
+
+ SafeRelease(mSwapChain);
+ mSwapChain = newSwapChain;
+
+ SafeRelease(mBackBuffer);
+ result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
+ ASSERT(SUCCEEDED(result));
+}
+
+}
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h
new file mode 100755
index 000000000..2e5cce1db
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h
@@ -0,0 +1,71 @@
+//
+// Copyright (c) 2012 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.
+//
+
+// SwapChain9.h: Defines a back-end specific class for the D3D9 swap chain.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_SWAPCHAIN9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_SWAPCHAIN9_H_
+
+#include "common/angleutils.h"
+#include "libANGLE/renderer/d3d/SwapChainD3D.h"
+#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
+
+namespace rx
+{
+class NativeWindow9;
+class Renderer9;
+
+class SwapChain9 : public SwapChainD3D
+{
+ public:
+ SwapChain9(Renderer9 *renderer,
+ NativeWindow9 *nativeWindow,
+ HANDLE shareHandle,
+ IUnknown *d3dTexture,
+ GLenum backBufferFormat,
+ GLenum depthBufferFormat,
+ EGLint orientation);
+ virtual ~SwapChain9();
+
+ EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight);
+ virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval);
+ virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height);
+ virtual void recreate();
+
+ RenderTargetD3D *getColorRenderTarget() override { return &mColorRenderTarget; }
+ RenderTargetD3D *getDepthStencilRenderTarget() override { return &mDepthStencilRenderTarget; }
+
+ virtual IDirect3DSurface9 *getRenderTarget();
+ virtual IDirect3DSurface9 *getDepthStencil();
+ virtual IDirect3DTexture9 *getOffscreenTexture();
+
+ EGLint getWidth() const { return mWidth; }
+ EGLint getHeight() const { return mHeight; }
+
+ void *getKeyedMutex() override;
+
+ private:
+ void release();
+
+ Renderer9 *mRenderer;
+ EGLint mWidth;
+ EGLint mHeight;
+ EGLint mSwapInterval;
+
+ NativeWindow9 *mNativeWindow;
+
+ IDirect3DSwapChain9 *mSwapChain;
+ IDirect3DSurface9 *mBackBuffer;
+ IDirect3DSurface9 *mRenderTarget;
+ IDirect3DSurface9 *mDepthStencil;
+ IDirect3DTexture9* mOffscreenTexture;
+
+ SurfaceRenderTarget9 mColorRenderTarget;
+ SurfaceRenderTarget9 mDepthStencilRenderTarget;
+};
+
+}
+#endif // LIBANGLE_RENDERER_D3D_D3D9_SWAPCHAIN9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp
new file mode 100755
index 000000000..db8765218
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp
@@ -0,0 +1,617 @@
+//
+// Copyright (c) 2012-2014 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.
+//
+
+// TextureStorage9.cpp: Implements the abstract rx::TextureStorage9 class and its concrete derived
+// classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the
+// D3D9 texture.
+
+#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h"
+
+#include "libANGLE/formatutils.h"
+#include "libANGLE/Texture.h"
+#include "libANGLE/renderer/d3d/EGLImageD3D.h"
+#include "libANGLE/renderer/d3d/TextureD3D.h"
+#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
+#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
+#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h"
+
+namespace rx
+{
+TextureStorage9::TextureStorage9(Renderer9 *renderer, DWORD usage)
+ : mTopLevel(0),
+ mMipLevels(0),
+ mTextureWidth(0),
+ mTextureHeight(0),
+ mInternalFormat(GL_NONE),
+ mTextureFormat(D3DFMT_UNKNOWN),
+ mRenderer(renderer),
+ mD3DUsage(usage),
+ mD3DPool(mRenderer->getTexturePool(usage))
+{
+}
+
+TextureStorage9::~TextureStorage9()
+{
+}
+
+DWORD TextureStorage9::GetTextureUsage(GLenum internalformat, bool renderTarget)
+{
+ DWORD d3dusage = 0;
+
+ const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
+ const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat);
+ if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
+ {
+ d3dusage |= D3DUSAGE_DEPTHSTENCIL;
+ }
+ else if (renderTarget && (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN))
+ {
+ d3dusage |= D3DUSAGE_RENDERTARGET;
+ }
+
+ return d3dusage;
+}
+
+
+bool TextureStorage9::isRenderTarget() const
+{
+ return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0;
+}
+
+bool TextureStorage9::isManaged() const
+{
+ return (mD3DPool == D3DPOOL_MANAGED);
+}
+
+bool TextureStorage9::supportsNativeMipmapFunction() const
+{
+ return false;
+}
+
+D3DPOOL TextureStorage9::getPool() const
+{
+ return mD3DPool;
+}
+
+DWORD TextureStorage9::getUsage() const
+{
+ return mD3DUsage;
+}
+
+int TextureStorage9::getTopLevel() const
+{
+ return mTopLevel;
+}
+
+int TextureStorage9::getLevelCount() const
+{
+ return static_cast<int>(mMipLevels) - mTopLevel;
+}
+
+gl::Error TextureStorage9::setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type,
+ const gl::PixelUnpackState &unpack, const uint8_t *pixelData)
+{
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain)
+ : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET)
+{
+ IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture();
+ mTexture = surfaceTexture;
+ mMipLevels = surfaceTexture->GetLevelCount();
+
+ mInternalFormat = swapchain->getRenderTargetInternalFormat();
+
+ D3DSURFACE_DESC surfaceDesc;
+ surfaceTexture->GetLevelDesc(0, &surfaceDesc);
+ mTextureWidth = surfaceDesc.Width;
+ mTextureHeight = surfaceDesc.Height;
+ mTextureFormat = surfaceDesc.Format;
+
+ mRenderTargets.resize(mMipLevels, nullptr);
+}
+
+TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels)
+ : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget))
+{
+ mTexture = NULL;
+
+ mInternalFormat = internalformat;
+
+ const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat);
+ mTextureFormat = d3dFormatInfo.texFormat;
+
+ d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &width, &height, &mTopLevel);
+ mTextureWidth = width;
+ mTextureHeight = height;
+ mMipLevels = mTopLevel + levels;
+
+ mRenderTargets.resize(levels, nullptr);
+}
+
+TextureStorage9_2D::~TextureStorage9_2D()
+{
+ SafeRelease(mTexture);
+ for (auto &renderTarget : mRenderTargets)
+ {
+ SafeDelete(renderTarget);
+ }
+}
+
+// Increments refcount on surface.
+// caller must Release() the returned surface
+gl::Error TextureStorage9_2D::getSurfaceLevel(GLenum target,
+ int level,
+ bool dirty,
+ IDirect3DSurface9 **outSurface)
+{
+ ASSERT(target == GL_TEXTURE_2D);
+
+ IDirect3DBaseTexture9 *baseTexture = NULL;
+ gl::Error error = getBaseTexture(&baseTexture);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ IDirect3DTexture9 *texture = static_cast<IDirect3DTexture9*>(baseTexture);
+
+ HRESULT result = texture->GetSurfaceLevel(level + mTopLevel, outSurface);
+
+ ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the surface from a texture, result: 0x%X.", result);
+ }
+
+ // With managed textures the driver needs to be informed of updates to the lower mipmap levels
+ if (level + mTopLevel != 0 && isManaged() && dirty)
+ {
+ texture->AddDirtyRect(NULL);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage9_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
+{
+ ASSERT(index.mipIndex < getLevelCount());
+
+ if (!mRenderTargets[index.mipIndex] && isRenderTarget())
+ {
+ IDirect3DBaseTexture9 *baseTexture = NULL;
+ gl::Error error = getBaseTexture(&baseTexture);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ IDirect3DSurface9 *surface = NULL;
+ error = getSurfaceLevel(GL_TEXTURE_2D, index.mipIndex, false, &surface);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ size_t textureMipLevel = mTopLevel + index.mipIndex;
+ size_t mipWidth = std::max<size_t>(mTextureWidth >> textureMipLevel, 1u);
+ size_t mipHeight = std::max<size_t>(mTextureHeight >> textureMipLevel, 1u);
+
+ baseTexture->AddRef();
+ mRenderTargets[index.mipIndex] = new TextureRenderTarget9(
+ baseTexture, textureMipLevel, surface, mInternalFormat, static_cast<GLsizei>(mipWidth),
+ static_cast<GLsizei>(mipHeight), 1, 0);
+ }
+
+ ASSERT(outRT);
+ *outRT = mRenderTargets[index.mipIndex];
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage9_2D::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex)
+{
+ IDirect3DSurface9 *upper = NULL;
+ gl::Error error = getSurfaceLevel(GL_TEXTURE_2D, sourceIndex.mipIndex, false, &upper);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ IDirect3DSurface9 *lower = NULL;
+ error = getSurfaceLevel(GL_TEXTURE_2D, destIndex.mipIndex, true, &lower);
+ if (error.isError())
+ {
+ SafeRelease(upper);
+ return error;
+ }
+
+ ASSERT(upper && lower);
+ error = mRenderer->boxFilter(upper, lower);
+
+ SafeRelease(upper);
+ SafeRelease(lower);
+
+ return error;
+}
+
+gl::Error TextureStorage9_2D::getBaseTexture(IDirect3DBaseTexture9 **outTexture)
+{
+ // if the width or height is not positive this should be treated as an incomplete texture
+ // we handle that here by skipping the d3d texture creation
+ if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0)
+ {
+ ASSERT(mMipLevels > 0);
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+ HRESULT result = device->CreateTexture(static_cast<unsigned int>(mTextureWidth),
+ static_cast<unsigned int>(mTextureHeight),
+ static_cast<unsigned int>(mMipLevels), getUsage(),
+ mTextureFormat, getPool(), &mTexture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D storage texture, result: 0x%X.", result);
+ }
+ }
+
+ *outTexture = mTexture;
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage9_2D::copyToStorage(TextureStorage *destStorage)
+{
+ ASSERT(destStorage);
+
+ TextureStorage9_2D *dest9 = GetAs<TextureStorage9_2D>(destStorage);
+
+ int levels = getLevelCount();
+ for (int i = 0; i < levels; ++i)
+ {
+ IDirect3DSurface9 *srcSurf = NULL;
+ gl::Error error = getSurfaceLevel(GL_TEXTURE_2D, i, false, &srcSurf);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ IDirect3DSurface9 *dstSurf = NULL;
+ error = dest9->getSurfaceLevel(GL_TEXTURE_2D, i, true, &dstSurf);
+ if (error.isError())
+ {
+ SafeRelease(srcSurf);
+ return error;
+ }
+
+ error = mRenderer->copyToRenderTarget(dstSurf, srcSurf, isManaged());
+
+ SafeRelease(srcSurf);
+ SafeRelease(dstSurf);
+
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+TextureStorage9_EGLImage::TextureStorage9_EGLImage(Renderer9 *renderer,
+ EGLImageD3D *image,
+ RenderTarget9 *renderTarget9)
+ : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET), mImage(image)
+{
+ mInternalFormat = renderTarget9->getInternalFormat();
+ mTextureFormat = renderTarget9->getD3DFormat();
+ mTextureWidth = renderTarget9->getWidth();
+ mTextureHeight = renderTarget9->getHeight();
+ mTopLevel = static_cast<int>(renderTarget9->getTextureLevel());
+ mMipLevels = mTopLevel + 1;
+}
+
+TextureStorage9_EGLImage::~TextureStorage9_EGLImage()
+{
+}
+
+gl::Error TextureStorage9_EGLImage::getSurfaceLevel(GLenum target,
+ int level,
+ bool,
+ IDirect3DSurface9 **outSurface)
+{
+ ASSERT(target == GL_TEXTURE_2D);
+ ASSERT(level == 0);
+
+ RenderTargetD3D *renderTargetD3D = nullptr;
+ gl::Error error = mImage->getRenderTarget(&renderTargetD3D);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTargetD3D);
+
+ *outSurface = renderTarget9->getSurface();
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage9_EGLImage::getRenderTarget(const gl::ImageIndex &index,
+ RenderTargetD3D **outRT)
+{
+ ASSERT(!index.hasLayer());
+ ASSERT(index.mipIndex == 0);
+
+ return mImage->getRenderTarget(outRT);
+}
+
+gl::Error TextureStorage9_EGLImage::getBaseTexture(IDirect3DBaseTexture9 **outTexture)
+{
+ RenderTargetD3D *renderTargetD3D = nullptr;
+ gl::Error error = mImage->getRenderTarget(&renderTargetD3D);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTargetD3D);
+ *outTexture = renderTarget9->getTexture();
+ ASSERT(*outTexture != nullptr);
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage9_EGLImage::generateMipmap(const gl::ImageIndex &, const gl::ImageIndex &)
+{
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+gl::Error TextureStorage9_EGLImage::copyToStorage(TextureStorage *destStorage)
+{
+ ASSERT(destStorage);
+ ASSERT(getLevelCount() == 1);
+
+ TextureStorage9 *dest9 = GetAs<TextureStorage9>(destStorage);
+
+ IDirect3DBaseTexture9 *destBaseTexture9 = nullptr;
+ gl::Error error = dest9->getBaseTexture(&destBaseTexture9);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ IDirect3DTexture9 *destTexture9 = static_cast<IDirect3DTexture9 *>(destBaseTexture9);
+
+ IDirect3DSurface9 *destSurface = nullptr;
+ HRESULT result = destTexture9->GetSurfaceLevel(destStorage->getTopLevel(), &destSurface);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to get the surface from a texture, result: 0x%X.", result);
+ }
+
+ RenderTargetD3D *sourceRenderTarget = nullptr;
+ error = mImage->getRenderTarget(&sourceRenderTarget);
+ if (error.isError())
+ {
+ SafeRelease(destSurface);
+ return error;
+ }
+
+ RenderTarget9 *sourceRenderTarget9 = GetAs<RenderTarget9>(sourceRenderTarget);
+ error =
+ mRenderer->copyToRenderTarget(destSurface, sourceRenderTarget9->getSurface(), isManaged());
+ if (error.isError())
+ {
+ SafeRelease(destSurface);
+ return error;
+ }
+
+ if (destStorage->getTopLevel() != 0)
+ {
+ destTexture9->AddDirtyRect(nullptr);
+ }
+
+ SafeRelease(destSurface);
+ return gl::Error(GL_NO_ERROR);
+}
+
+TextureStorage9_Cube::TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly)
+ : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget))
+{
+ mTexture = NULL;
+ for (size_t i = 0; i < CUBE_FACE_COUNT; ++i)
+ {
+ mRenderTarget[i] = NULL;
+ }
+
+ mInternalFormat = internalformat;
+
+ const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat);
+ mTextureFormat = d3dFormatInfo.texFormat;
+
+ int height = size;
+ d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &size, &height, &mTopLevel);
+ mTextureWidth = size;
+ mTextureHeight = size;
+ mMipLevels = mTopLevel + levels;
+}
+
+TextureStorage9_Cube::~TextureStorage9_Cube()
+{
+ SafeRelease(mTexture);
+
+ for (size_t i = 0; i < CUBE_FACE_COUNT; ++i)
+ {
+ SafeDelete(mRenderTarget[i]);
+ }
+}
+
+// Increments refcount on surface.
+// caller must Release() the returned surface
+gl::Error TextureStorage9_Cube::getSurfaceLevel(GLenum target,
+ int level,
+ bool dirty,
+ IDirect3DSurface9 **outSurface)
+{
+ IDirect3DBaseTexture9 *baseTexture = NULL;
+ gl::Error error = getBaseTexture(&baseTexture);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ IDirect3DCubeTexture9 *texture = static_cast<IDirect3DCubeTexture9*>(baseTexture);
+
+ D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(target);
+ HRESULT result = texture->GetCubeMapSurface(face, level, outSurface);
+
+ ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the surface from a texture, result: 0x%X.", result);
+ }
+
+ // With managed textures the driver needs to be informed of updates to the lower mipmap levels
+ if (level != 0 && isManaged() && dirty)
+ {
+ texture->AddDirtyRect(face, NULL);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage9_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
+{
+ ASSERT(outRT);
+ ASSERT(index.mipIndex == 0);
+ ASSERT(index.layerIndex >= 0 && static_cast<size_t>(index.layerIndex) < CUBE_FACE_COUNT);
+
+ if (mRenderTarget[index.layerIndex] == NULL && isRenderTarget())
+ {
+ IDirect3DBaseTexture9 *baseTexture = NULL;
+ gl::Error error = getBaseTexture(&baseTexture);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ IDirect3DSurface9 *surface = NULL;
+ error = getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index.layerIndex,
+ mTopLevel + index.mipIndex, false, &surface);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ baseTexture->AddRef();
+ mRenderTarget[index.layerIndex] = new TextureRenderTarget9(
+ baseTexture, mTopLevel + index.mipIndex, surface, mInternalFormat,
+ static_cast<GLsizei>(mTextureWidth), static_cast<GLsizei>(mTextureHeight), 1, 0);
+ }
+
+ *outRT = mRenderTarget[index.layerIndex];
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage9_Cube::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex)
+{
+ IDirect3DSurface9 *upper = NULL;
+ gl::Error error = getSurfaceLevel(sourceIndex.type, sourceIndex.mipIndex, false, &upper);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ IDirect3DSurface9 *lower = NULL;
+ error = getSurfaceLevel(destIndex.type, destIndex.mipIndex, true, &lower);
+ if (error.isError())
+ {
+ SafeRelease(upper);
+ return error;
+ }
+
+ ASSERT(upper && lower);
+ error = mRenderer->boxFilter(upper, lower);
+
+ SafeRelease(upper);
+ SafeRelease(lower);
+
+ return error;
+}
+
+gl::Error TextureStorage9_Cube::getBaseTexture(IDirect3DBaseTexture9 **outTexture)
+{
+ // if the size is not positive this should be treated as an incomplete texture
+ // we handle that here by skipping the d3d texture creation
+ if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0)
+ {
+ ASSERT(mMipLevels > 0);
+ ASSERT(mTextureWidth == mTextureHeight);
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+ HRESULT result = device->CreateCubeTexture(
+ static_cast<unsigned int>(mTextureWidth), static_cast<unsigned int>(mMipLevels),
+ getUsage(), mTextureFormat, getPool(), &mTexture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube storage texture, result: 0x%X.", result);
+ }
+ }
+
+ *outTexture = mTexture;
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage9_Cube::copyToStorage(TextureStorage *destStorage)
+{
+ ASSERT(destStorage);
+
+ TextureStorage9_Cube *dest9 = GetAs<TextureStorage9_Cube>(destStorage);
+
+ int levels = getLevelCount();
+ for (int f = 0; f < static_cast<int>(CUBE_FACE_COUNT); f++)
+ {
+ for (int i = 0; i < levels; i++)
+ {
+ IDirect3DSurface9 *srcSurf = NULL;
+ gl::Error error =
+ getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false, &srcSurf);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ IDirect3DSurface9 *dstSurf = NULL;
+ error = dest9->getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true, &dstSurf);
+ if (error.isError())
+ {
+ SafeRelease(srcSurf);
+ return error;
+ }
+
+ error = mRenderer->copyToRenderTarget(dstSurf, srcSurf, isManaged());
+
+ SafeRelease(srcSurf);
+ SafeRelease(dstSurf);
+
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+}
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h
new file mode 100755
index 000000000..f0455a9b7
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h
@@ -0,0 +1,134 @@
+//
+// Copyright (c) 2012-2013 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.
+//
+
+// TextureStorage9.h: Defines the abstract rx::TextureStorage9 class and its concrete derived
+// classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the
+// D3D9 texture.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_TEXTURESTORAGE9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_TEXTURESTORAGE9_H_
+
+#include "libANGLE/renderer/d3d/TextureStorage.h"
+#include "common/debug.h"
+
+namespace rx
+{
+class EGLImageD3D;
+class Renderer9;
+class SwapChain9;
+class RenderTargetD3D;
+class RenderTarget9;
+
+class TextureStorage9 : public TextureStorage
+{
+ public:
+ virtual ~TextureStorage9();
+
+ static DWORD GetTextureUsage(GLenum internalformat, bool renderTarget);
+
+ D3DPOOL getPool() const;
+ DWORD getUsage() const;
+
+ virtual gl::Error getSurfaceLevel(GLenum target,
+ int level,
+ bool dirty,
+ IDirect3DSurface9 **outSurface) = 0;
+ virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture) = 0;
+ virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) = 0;
+
+ virtual int getTopLevel() const;
+ virtual bool isRenderTarget() const;
+ virtual bool isManaged() const;
+ bool supportsNativeMipmapFunction() const override;
+ virtual int getLevelCount() const;
+
+ virtual gl::Error setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type,
+ const gl::PixelUnpackState &unpack, const uint8_t *pixelData);
+
+ protected:
+ int mTopLevel;
+ size_t mMipLevels;
+ size_t mTextureWidth;
+ size_t mTextureHeight;
+ GLenum mInternalFormat;
+ D3DFORMAT mTextureFormat;
+
+ Renderer9 *mRenderer;
+
+ TextureStorage9(Renderer9 *renderer, DWORD usage);
+
+ private:
+ const DWORD mD3DUsage;
+ const D3DPOOL mD3DPool;
+};
+
+class TextureStorage9_2D : public TextureStorage9
+{
+ public:
+ TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain);
+ TextureStorage9_2D(Renderer9 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels);
+ virtual ~TextureStorage9_2D();
+
+ gl::Error getSurfaceLevel(GLenum target,
+ int level,
+ bool dirty,
+ IDirect3DSurface9 **outSurface) override;
+ virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT);
+ virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture);
+ virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex);
+ virtual gl::Error copyToStorage(TextureStorage *destStorage);
+
+ private:
+ IDirect3DTexture9 *mTexture;
+ std::vector<RenderTarget9 *> mRenderTargets;
+};
+
+class TextureStorage9_EGLImage final : public TextureStorage9
+{
+ public:
+ TextureStorage9_EGLImage(Renderer9 *renderer, EGLImageD3D *image, RenderTarget9 *renderTarget9);
+ ~TextureStorage9_EGLImage() override;
+
+ gl::Error getSurfaceLevel(GLenum target,
+ int level,
+ bool dirty,
+ IDirect3DSurface9 **outSurface) override;
+ gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) override;
+ gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture) override;
+ gl::Error generateMipmap(const gl::ImageIndex &sourceIndex,
+ const gl::ImageIndex &destIndex) override;
+ gl::Error copyToStorage(TextureStorage *destStorage) override;
+
+ private:
+ EGLImageD3D *mImage;
+};
+
+class TextureStorage9_Cube : public TextureStorage9
+{
+ public:
+ TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly);
+ virtual ~TextureStorage9_Cube();
+
+ gl::Error getSurfaceLevel(GLenum target,
+ int level,
+ bool dirty,
+ IDirect3DSurface9 **outSurface) override;
+ virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT);
+ virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture);
+ virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex);
+ virtual gl::Error copyToStorage(TextureStorage *destStorage);
+
+ private:
+ static const size_t CUBE_FACE_COUNT = 6;
+
+ IDirect3DCubeTexture9 *mTexture;
+ RenderTarget9 *mRenderTarget[CUBE_FACE_COUNT];
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_TEXTURESTORAGE9_H_
+
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h
new file mode 100755
index 000000000..28b8717e6
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h
@@ -0,0 +1,29 @@
+//
+// Copyright 2014 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.
+//
+
+// VertexArray9.h: Defines the rx::VertexArray9 class which implements rx::VertexArrayImpl.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_
+
+#include "libANGLE/renderer/VertexArrayImpl.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+
+namespace rx
+{
+class Renderer9;
+
+class VertexArray9 : public VertexArrayImpl
+{
+ public:
+ VertexArray9(const gl::VertexArrayState &data) : VertexArrayImpl(data) {}
+
+ virtual ~VertexArray9() { }
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp
new file mode 100755
index 000000000..c5c07c348
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp
@@ -0,0 +1,165 @@
+//
+// Copyright (c) 2002-2012 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.
+//
+
+// VertexBuffer9.cpp: Defines the D3D9 VertexBuffer implementation.
+
+#include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
+#include "libANGLE/renderer/d3d/d3d9/vertexconversion.h"
+#include "libANGLE/renderer/d3d/BufferD3D.h"
+#include "libANGLE/VertexAttribute.h"
+#include "libANGLE/Buffer.h"
+
+namespace rx
+{
+
+VertexBuffer9::VertexBuffer9(Renderer9 *renderer) : mRenderer(renderer)
+{
+ mVertexBuffer = NULL;
+ mBufferSize = 0;
+ mDynamicUsage = false;
+}
+
+VertexBuffer9::~VertexBuffer9()
+{
+ SafeRelease(mVertexBuffer);
+}
+
+gl::Error VertexBuffer9::initialize(unsigned int size, bool dynamicUsage)
+{
+ SafeRelease(mVertexBuffer);
+
+ updateSerial();
+
+ if (size > 0)
+ {
+ DWORD flags = D3DUSAGE_WRITEONLY;
+ if (dynamicUsage)
+ {
+ flags |= D3DUSAGE_DYNAMIC;
+ }
+
+ HRESULT result = mRenderer->createVertexBuffer(size, flags, &mVertexBuffer);
+
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size);
+ }
+ }
+
+ mBufferSize = size;
+ mDynamicUsage = dynamicUsage;
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib,
+ GLenum currentValueType,
+ GLint start,
+ GLsizei count,
+ GLsizei instances,
+ unsigned int offset,
+ const uint8_t *sourceData)
+{
+ if (!mVertexBuffer)
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized.");
+ }
+
+ int inputStride = static_cast<int>(gl::ComputeVertexAttributeStride(attrib));
+ int elementSize = static_cast<int>(gl::ComputeVertexAttributeTypeSize(attrib));
+
+ DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0;
+
+ uint8_t *mapPtr = nullptr;
+
+ auto errorOrMapSize = mRenderer->getVertexSpaceRequired(attrib, count, instances);
+ if (errorOrMapSize.isError())
+ {
+ return errorOrMapSize.getError();
+ }
+
+ unsigned int mapSize = errorOrMapSize.getResult();
+
+ HRESULT result = mVertexBuffer->Lock(offset, mapSize, reinterpret_cast<void**>(&mapPtr), lockFlags);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal vertex buffer, HRESULT: 0x%08x.", result);
+ }
+
+ const uint8_t *input = sourceData;
+
+ if (instances == 0 || attrib.divisor == 0)
+ {
+ input += inputStride * start;
+ }
+
+ gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib, currentValueType);
+ const d3d9::VertexFormat &d3dVertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormatType);
+ bool needsConversion = (d3dVertexInfo.conversionType & VERTEX_CONVERT_CPU) > 0;
+
+ if (!needsConversion && inputStride == elementSize)
+ {
+ size_t copySize = static_cast<size_t>(count) * static_cast<size_t>(inputStride);
+ memcpy(mapPtr, input, copySize);
+ }
+ else
+ {
+ d3dVertexInfo.copyFunction(input, inputStride, count, mapPtr);
+ }
+
+ mVertexBuffer->Unlock();
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+unsigned int VertexBuffer9::getBufferSize() const
+{
+ return mBufferSize;
+}
+
+gl::Error VertexBuffer9::setBufferSize(unsigned int size)
+{
+ if (size > mBufferSize)
+ {
+ return initialize(size, mDynamicUsage);
+ }
+ else
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+}
+
+gl::Error VertexBuffer9::discard()
+{
+ if (!mVertexBuffer)
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized.");
+ }
+
+ void *dummy;
+ HRESULT result;
+
+ result = mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal buffer for discarding, HRESULT: 0x%08x", result);
+ }
+
+ result = mVertexBuffer->Unlock();
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal buffer for discarding, HRESULT: 0x%08x", result);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+IDirect3DVertexBuffer9 * VertexBuffer9::getBuffer() const
+{
+ return mVertexBuffer;
+}
+} // namespace rx
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h
new file mode 100755
index 000000000..0d2d8c288
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h
@@ -0,0 +1,50 @@
+//
+// Copyright (c) 2002-2012 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.
+//
+
+// VertexBuffer9.h: Defines the D3D9 VertexBuffer implementation.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXBUFFER9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXBUFFER9_H_
+
+#include "libANGLE/renderer/d3d/VertexBuffer.h"
+
+namespace rx
+{
+class Renderer9;
+
+class VertexBuffer9 : public VertexBuffer
+{
+ public:
+ explicit VertexBuffer9(Renderer9 *renderer);
+
+ gl::Error initialize(unsigned int size, bool dynamicUsage) override;
+
+ gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib,
+ GLenum currentValueType,
+ GLint start,
+ GLsizei count,
+ GLsizei instances,
+ unsigned int offset,
+ const uint8_t *sourceData) override;
+
+ unsigned int getBufferSize() const override;
+ gl::Error setBufferSize(unsigned int size) override;
+ gl::Error discard() override;
+
+ IDirect3DVertexBuffer9 *getBuffer() const;
+
+ private:
+ ~VertexBuffer9() override;
+ Renderer9 *mRenderer;
+
+ IDirect3DVertexBuffer9 *mVertexBuffer;
+ unsigned int mBufferSize;
+ bool mDynamicUsage;
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXBUFFER9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp
new file mode 100755
index 000000000..c2e935e71
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp
@@ -0,0 +1,255 @@
+//
+// Copyright (c) 2012 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.
+//
+
+// VertexDeclarationCache.cpp: Implements a helper class to construct and cache vertex declarations.
+
+#include "libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h"
+
+#include "libANGLE/VertexAttribute.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/d3d/ProgramD3D.h"
+#include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h"
+#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
+
+namespace rx
+{
+
+VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0)
+{
+ for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+ {
+ mVertexDeclCache[i].vertexDeclaration = NULL;
+ mVertexDeclCache[i].lruCount = 0;
+ }
+
+ for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ mAppliedVBs[i].serial = 0;
+ }
+
+ mLastSetVDecl = NULL;
+ mInstancingEnabled = true;
+}
+
+VertexDeclarationCache::~VertexDeclarationCache()
+{
+ for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+ {
+ SafeRelease(mVertexDeclCache[i].vertexDeclaration);
+ }
+}
+
+gl::Error VertexDeclarationCache::applyDeclaration(
+ IDirect3DDevice9 *device,
+ const std::vector<TranslatedAttribute> &attributes,
+ gl::Program *program,
+ GLint start,
+ GLsizei instances,
+ GLsizei *repeatDraw)
+{
+ ASSERT(gl::MAX_VERTEX_ATTRIBS >= attributes.size());
+
+ *repeatDraw = 1;
+
+ const size_t invalidAttribIndex = attributes.size();
+ size_t indexedAttribute = invalidAttribIndex;
+ size_t instancedAttribute = invalidAttribIndex;
+
+ if (instances == 0)
+ {
+ for (size_t i = 0; i < attributes.size(); ++i)
+ {
+ if (attributes[i].divisor != 0)
+ {
+ // If a divisor is set, it still applies even if an instanced draw was not used, so treat
+ // as a single-instance draw.
+ instances = 1;
+ break;
+ }
+ }
+ }
+
+ if (instances > 0)
+ {
+ // Find an indexed attribute to be mapped to D3D stream 0
+ for (size_t i = 0; i < attributes.size(); i++)
+ {
+ if (attributes[i].active)
+ {
+ if (indexedAttribute == invalidAttribIndex && attributes[i].divisor == 0)
+ {
+ indexedAttribute = i;
+ }
+ else if (instancedAttribute == invalidAttribIndex && attributes[i].divisor != 0)
+ {
+ instancedAttribute = i;
+ }
+ if (indexedAttribute != invalidAttribIndex && instancedAttribute != invalidAttribIndex)
+ break; // Found both an indexed and instanced attribute
+ }
+ }
+
+ // The validation layer checks that there is at least one active attribute with a zero divisor as per
+ // the GL_ANGLE_instanced_arrays spec.
+ ASSERT(indexedAttribute != invalidAttribIndex || !attributes.size());
+ }
+
+ D3DCAPS9 caps;
+ device->GetDeviceCaps(&caps);
+
+ D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1];
+ D3DVERTEXELEMENT9 *element = &elements[0];
+
+ ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
+ const auto &semanticIndexes = programD3D->getAttribLocationToD3DSemantics();
+
+ for (size_t i = 0; i < attributes.size(); i++)
+ {
+ if (attributes[i].active)
+ {
+ // Directly binding the storage buffer is not supported for d3d9
+ ASSERT(attributes[i].storage == NULL);
+
+ int stream = static_cast<int>(i);
+
+ if (instances > 0)
+ {
+ // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced.
+ if (instancedAttribute == invalidAttribIndex)
+ {
+ *repeatDraw = instances;
+ }
+ else
+ {
+ if (i == indexedAttribute)
+ {
+ stream = 0;
+ }
+ else if (i == 0)
+ {
+ stream = static_cast<int>(indexedAttribute);
+ }
+
+ UINT frequency = 1;
+
+ if (attributes[i].divisor == 0)
+ {
+ frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances;
+ }
+ else
+ {
+ frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor;
+ }
+
+ device->SetStreamSourceFreq(stream, frequency);
+ mInstancingEnabled = true;
+ }
+ }
+
+ VertexBuffer9 *vertexBuffer = GetAs<VertexBuffer9>(attributes[i].vertexBuffer.get());
+
+ unsigned int offset = 0;
+ ANGLE_TRY_RESULT(attributes[i].computeOffset(start), offset);
+
+ if (mAppliedVBs[stream].serial != attributes[i].serial ||
+ mAppliedVBs[stream].stride != attributes[i].stride ||
+ mAppliedVBs[stream].offset != offset)
+ {
+ device->SetStreamSource(stream, vertexBuffer->getBuffer(), offset,
+ attributes[i].stride);
+ mAppliedVBs[stream].serial = attributes[i].serial;
+ mAppliedVBs[stream].stride = attributes[i].stride;
+ mAppliedVBs[stream].offset = offset;
+ }
+
+ gl::VertexFormatType vertexformatType = gl::GetVertexFormatType(*attributes[i].attribute, GL_FLOAT);
+ const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(caps.DeclTypes, vertexformatType);
+
+ element->Stream = static_cast<WORD>(stream);
+ element->Offset = 0;
+ element->Type = static_cast<BYTE>(d3d9VertexInfo.nativeFormat);
+ element->Method = D3DDECLMETHOD_DEFAULT;
+ element->Usage = D3DDECLUSAGE_TEXCOORD;
+ element->UsageIndex = static_cast<BYTE>(semanticIndexes[i]);
+ element++;
+ }
+ }
+
+ if (instances == 0 || instancedAttribute == invalidAttribIndex)
+ {
+ if (mInstancingEnabled)
+ {
+ for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ device->SetStreamSourceFreq(i, 1);
+ }
+
+ mInstancingEnabled = false;
+ }
+ }
+
+ static const D3DVERTEXELEMENT9 end = D3DDECL_END();
+ *(element++) = end;
+
+ for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+ {
+ VertexDeclCacheEntry *entry = &mVertexDeclCache[i];
+ if (memcmp(entry->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 && entry->vertexDeclaration)
+ {
+ entry->lruCount = ++mMaxLru;
+ if(entry->vertexDeclaration != mLastSetVDecl)
+ {
+ device->SetVertexDeclaration(entry->vertexDeclaration);
+ mLastSetVDecl = entry->vertexDeclaration;
+ }
+
+ return gl::Error(GL_NO_ERROR);
+ }
+ }
+
+ VertexDeclCacheEntry *lastCache = mVertexDeclCache;
+
+ for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+ {
+ if (mVertexDeclCache[i].lruCount < lastCache->lruCount)
+ {
+ lastCache = &mVertexDeclCache[i];
+ }
+ }
+
+ if (lastCache->vertexDeclaration != NULL)
+ {
+ SafeRelease(lastCache->vertexDeclaration);
+ // mLastSetVDecl is set to the replacement, so we don't have to worry
+ // about it.
+ }
+
+ memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9));
+ HRESULT result = device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal vertex declaration, result: 0x%X.", result);
+ }
+
+ device->SetVertexDeclaration(lastCache->vertexDeclaration);
+ mLastSetVDecl = lastCache->vertexDeclaration;
+ lastCache->lruCount = ++mMaxLru;
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+void VertexDeclarationCache::markStateDirty()
+{
+ for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ mAppliedVBs[i].serial = 0;
+ }
+
+ mLastSetVDecl = NULL;
+ mInstancingEnabled = true; // Forces it to be disabled when not used
+}
+
+}
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h
new file mode 100755
index 000000000..7bd7cabae
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h
@@ -0,0 +1,65 @@
+//
+// Copyright (c) 2012 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.
+//
+
+// VertexDeclarationCache.h: Defines a helper class to construct and cache vertex declarations.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXDECLARATIONCACHE_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXDECLARATIONCACHE_H_
+
+#include "libANGLE/Error.h"
+#include "libANGLE/renderer/d3d/VertexDataManager.h"
+
+namespace gl
+{
+class VertexDataManager;
+class Program;
+}
+
+namespace rx
+{
+
+class VertexDeclarationCache
+{
+ public:
+ VertexDeclarationCache();
+ ~VertexDeclarationCache();
+
+ gl::Error applyDeclaration(IDirect3DDevice9 *device,
+ const std::vector<TranslatedAttribute> &attributes,
+ gl::Program *program,
+ GLint start,
+ GLsizei instances,
+ GLsizei *repeatDraw);
+
+ void markStateDirty();
+
+ private:
+ UINT mMaxLru;
+
+ enum { NUM_VERTEX_DECL_CACHE_ENTRIES = 32 };
+
+ struct VBData
+ {
+ unsigned int serial;
+ unsigned int stride;
+ unsigned int offset;
+ };
+
+ VBData mAppliedVBs[gl::MAX_VERTEX_ATTRIBS];
+ IDirect3DVertexDeclaration9 *mLastSetVDecl;
+ bool mInstancingEnabled;
+
+ struct VertexDeclCacheEntry
+ {
+ D3DVERTEXELEMENT9 cachedElements[gl::MAX_VERTEX_ATTRIBS + 1];
+ UINT lruCount;
+ IDirect3DVertexDeclaration9 *vertexDeclaration;
+ } mVertexDeclCache[NUM_VERTEX_DECL_CACHE_ENTRIES];
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXDECLARATIONCACHE_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp
new file mode 100755
index 000000000..7cff9a117
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp
@@ -0,0 +1,659 @@
+//
+// Copyright (c) 2013-2014 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.
+//
+
+// formatutils9.cpp: Queries for GL image formats and their translations to D3D9
+// formats.
+
+#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
+
+#include "image_util/copyimage.h"
+#include "image_util/generatemip.h"
+#include "image_util/loadimage.h"
+
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+#include "libANGLE/renderer/d3d/d3d9/vertexconversion.h"
+
+using namespace angle;
+
+namespace rx
+{
+
+namespace d3d9
+{
+
+constexpr D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Z')));
+constexpr D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N', 'U', 'L', 'L')));
+
+// A map to determine the pixel size and mip generation function of a given D3D format
+typedef std::map<D3DFORMAT, D3DFormat> D3D9FormatInfoMap;
+
+constexpr D3DFormat::D3DFormat()
+ : pixelBytes(0),
+ blockWidth(0),
+ blockHeight(0),
+ redBits(0),
+ greenBits(0),
+ blueBits(0),
+ alphaBits(0),
+ luminanceBits(0),
+ depthBits(0),
+ stencilBits(0),
+ formatID(angle::Format::ID::NONE)
+{
+}
+
+constexpr D3DFormat::D3DFormat(GLuint bits,
+ GLuint blockWidth,
+ GLuint blockHeight,
+ GLuint redBits,
+ GLuint greenBits,
+ GLuint blueBits,
+ GLuint alphaBits,
+ GLuint lumBits,
+ GLuint depthBits,
+ GLuint stencilBits,
+ Format::ID formatID)
+ : pixelBytes(bits / 8),
+ blockWidth(blockWidth),
+ blockHeight(blockHeight),
+ redBits(redBits),
+ greenBits(greenBits),
+ blueBits(blueBits),
+ alphaBits(alphaBits),
+ luminanceBits(lumBits),
+ depthBits(depthBits),
+ stencilBits(stencilBits),
+ formatID(formatID)
+{
+}
+
+const D3DFormat &GetD3DFormatInfo(D3DFORMAT format)
+{
+ if (format == D3DFMT_NULL)
+ {
+ static constexpr D3DFormat info(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Format::ID::NONE);
+ return info;
+ }
+
+ if (format == D3DFMT_INTZ)
+ {
+ static constexpr D3DFormat info(32, 1, 1, 0, 0, 0, 0, 0, 24, 8,
+ Format::ID::D24_UNORM_S8_UINT);
+ return info;
+ }
+
+ switch (format)
+ {
+ case D3DFMT_UNKNOWN:
+ {
+ static constexpr D3DFormat info(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Format::ID::NONE);
+ return info;
+ }
+
+ case D3DFMT_L8:
+ {
+ static constexpr D3DFormat info(8, 1, 1, 0, 0, 0, 0, 8, 0, 0, Format::ID::L8_UNORM);
+ return info;
+ }
+ case D3DFMT_A8:
+ {
+ static constexpr D3DFormat info(8, 1, 1, 0, 0, 0, 8, 0, 0, 0, Format::ID::A8_UNORM);
+ return info;
+ }
+ case D3DFMT_A8L8:
+ {
+ static constexpr D3DFormat info(16, 1, 1, 0, 0, 0, 8, 8, 0, 0, Format::ID::L8A8_UNORM);
+ return info;
+ }
+
+ case D3DFMT_A4R4G4B4:
+ {
+ static constexpr D3DFormat info(16, 1, 1, 4, 4, 4, 4, 0, 0, 0,
+ Format::ID::B4G4R4A4_UNORM);
+ return info;
+ }
+ case D3DFMT_A1R5G5B5:
+ {
+ static constexpr D3DFormat info(16, 1, 1, 5, 5, 5, 1, 0, 0, 0,
+ Format::ID::B5G5R5A1_UNORM);
+ return info;
+ }
+ case D3DFMT_R5G6B5:
+ {
+ static constexpr D3DFormat info(16, 1, 1, 5, 6, 5, 0, 0, 0, 0,
+ Format::ID::R5G6B5_UNORM);
+ return info;
+ }
+ case D3DFMT_X8R8G8B8:
+ {
+ static constexpr D3DFormat info(32, 1, 1, 8, 8, 8, 0, 0, 0, 0,
+ Format::ID::B8G8R8X8_UNORM);
+ return info;
+ }
+ case D3DFMT_A8R8G8B8:
+ {
+ static constexpr D3DFormat info(32, 1, 1, 8, 8, 8, 8, 0, 0, 0,
+ Format::ID::B8G8R8A8_UNORM);
+ return info;
+ }
+
+ case D3DFMT_R16F:
+ {
+ static constexpr D3DFormat info(16, 1, 1, 16, 0, 0, 0, 0, 0, 0, Format::ID::R16_FLOAT);
+ return info;
+ }
+ case D3DFMT_G16R16F:
+ {
+ static constexpr D3DFormat info(32, 1, 1, 16, 16, 0, 0, 0, 0, 0,
+ Format::ID::R16G16_FLOAT);
+ return info;
+ }
+ case D3DFMT_A16B16G16R16F:
+ {
+ static constexpr D3DFormat info(64, 1, 1, 16, 16, 16, 16, 0, 0, 0,
+ Format::ID::R16G16B16A16_FLOAT);
+ return info;
+ }
+ case D3DFMT_R32F:
+ {
+ static constexpr D3DFormat info(32, 1, 1, 32, 0, 0, 0, 0, 0, 0, Format::ID::R32_FLOAT);
+ return info;
+ }
+ case D3DFMT_G32R32F:
+ {
+ static constexpr D3DFormat info(64, 1, 1, 32, 32, 0, 0, 0, 0, 0,
+ Format::ID::R32G32_FLOAT);
+ return info;
+ }
+ case D3DFMT_A32B32G32R32F:
+ {
+ static constexpr D3DFormat info(128, 1, 1, 32, 32, 32, 32, 0, 0, 0,
+ Format::ID::R32G32B32A32_FLOAT);
+ return info;
+ }
+
+ case D3DFMT_D16:
+ {
+ static constexpr D3DFormat info(16, 1, 1, 0, 0, 0, 0, 0, 16, 0, Format::ID::D16_UNORM);
+ return info;
+ }
+ case D3DFMT_D24S8:
+ {
+ static constexpr D3DFormat info(32, 1, 1, 0, 0, 0, 0, 0, 24, 8,
+ Format::ID::D24_UNORM_S8_UINT);
+ return info;
+ }
+ case D3DFMT_D24X8:
+ {
+ static constexpr D3DFormat info(32, 1, 1, 0, 0, 0, 0, 0, 24, 0, Format::ID::D16_UNORM);
+ return info;
+ }
+ case D3DFMT_D32:
+ {
+ static constexpr D3DFormat info(32, 1, 1, 0, 0, 0, 0, 0, 32, 0, Format::ID::D32_UNORM);
+ return info;
+ }
+
+ case D3DFMT_DXT1:
+ {
+ static constexpr D3DFormat info(64, 4, 4, 0, 0, 0, 0, 0, 0, 0,
+ Format::ID::BC1_RGBA_UNORM_BLOCK);
+ return info;
+ }
+ case D3DFMT_DXT3:
+ {
+ static constexpr D3DFormat info(128, 4, 4, 0, 0, 0, 0, 0, 0, 0,
+ Format::ID::BC2_RGBA_UNORM_BLOCK);
+ return info;
+ }
+ case D3DFMT_DXT5:
+ {
+ static constexpr D3DFormat info(128, 4, 4, 0, 0, 0, 0, 0, 0, 0,
+ Format::ID::BC3_RGBA_UNORM_BLOCK);
+ return info;
+ }
+
+ default:
+ {
+ static constexpr D3DFormat defaultInfo;
+ return defaultInfo;
+ }
+ }
+}
+
+typedef std::pair<GLint, InitializeTextureDataFunction> InternalFormatInitialzerPair;
+typedef std::map<GLint, InitializeTextureDataFunction> InternalFormatInitialzerMap;
+
+static InternalFormatInitialzerMap BuildInternalFormatInitialzerMap()
+{
+ using namespace angle; // For image initialization functions
+
+ InternalFormatInitialzerMap map;
+
+ map.insert(InternalFormatInitialzerPair(GL_RGB16F, Initialize4ComponentData<GLhalf, 0x0000, 0x0000, 0x0000, gl::Float16One>));
+ map.insert(InternalFormatInitialzerPair(GL_RGB32F, Initialize4ComponentData<GLfloat, 0x00000000, 0x00000000, 0x00000000, gl::Float32One>));
+
+ return map;
+}
+
+static void UnreachableLoad(size_t width, size_t height, size_t depth,
+ const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
+ uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch)
+{
+ UNREACHABLE();
+}
+
+typedef std::pair<GLenum, TextureFormat> D3D9FormatPair;
+typedef std::map<GLenum, TextureFormat> D3D9FormatMap;
+
+TextureFormat::TextureFormat()
+ : texFormat(D3DFMT_UNKNOWN),
+ renderFormat(D3DFMT_UNKNOWN),
+ dataInitializerFunction(NULL),
+ loadFunction(UnreachableLoad)
+{
+}
+
+static inline void InsertD3D9FormatInfo(D3D9FormatMap *map, GLenum internalFormat, D3DFORMAT texFormat,
+ D3DFORMAT renderFormat, LoadImageFunction loadFunction)
+{
+ TextureFormat info;
+ info.texFormat = texFormat;
+ info.renderFormat = renderFormat;
+
+ static const InternalFormatInitialzerMap dataInitializationMap = BuildInternalFormatInitialzerMap();
+ InternalFormatInitialzerMap::const_iterator dataInitIter = dataInitializationMap.find(internalFormat);
+ info.dataInitializerFunction = (dataInitIter != dataInitializationMap.end()) ? dataInitIter->second : NULL;
+
+ info.loadFunction = loadFunction;
+
+ map->insert(std::make_pair(internalFormat, info));
+}
+
+static D3D9FormatMap BuildD3D9FormatMap()
+{
+ using namespace angle; // For image loading functions
+
+ D3D9FormatMap map;
+
+ // clang-format off
+ // | Internal format | Texture format | Render format | Load function |
+ InsertD3D9FormatInfo(&map, GL_NONE, D3DFMT_NULL, D3DFMT_NULL, UnreachableLoad );
+
+ // We choose to downsample the GL_DEPTH_COMPONENT32_OES format to a 24-bit format because D3DFMT_D32 is not widely
+ // supported. We're allowed to do this because:
+ // - The ES spec 2.0.25 sec 3.7.1 states that we're allowed to store texture formats with internal format
+ // resolutions of our own choosing.
+ // - OES_depth_texture states that downsampling of the depth formats is allowed.
+ // - ANGLE_depth_texture does not state minimum required resolutions of the depth texture formats it
+ // introduces.
+ // In ES3 however, there are minimum resolutions for the texture formats and this would not be allowed.
+
+ InsertD3D9FormatInfo(&map, GL_DEPTH_COMPONENT16, D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad );
+ InsertD3D9FormatInfo(&map, GL_DEPTH_COMPONENT32_OES, D3DFMT_INTZ, D3DFMT_D24X8, UnreachableLoad );
+ InsertD3D9FormatInfo(&map, GL_DEPTH24_STENCIL8_OES, D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad );
+ InsertD3D9FormatInfo(&map, GL_STENCIL_INDEX8, D3DFMT_UNKNOWN, D3DFMT_D24S8, UnreachableLoad ); // TODO: What's the texture format?
+
+ InsertD3D9FormatInfo(&map, GL_RGBA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative<GLfloat, 4> );
+ InsertD3D9FormatInfo(&map, GL_RGB32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative3To4<GLfloat, gl::Float32One>);
+ InsertD3D9FormatInfo(&map, GL_RG32F_EXT, D3DFMT_G32R32F, D3DFMT_G32R32F, LoadToNative<GLfloat, 2> );
+ InsertD3D9FormatInfo(&map, GL_R32F_EXT, D3DFMT_R32F, D3DFMT_R32F, LoadToNative<GLfloat, 1> );
+ InsertD3D9FormatInfo(&map, GL_ALPHA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadA32FToRGBA32F );
+ InsertD3D9FormatInfo(&map, GL_LUMINANCE32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadL32FToRGBA32F );
+ InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadLA32FToRGBA32F );
+
+ InsertD3D9FormatInfo(&map, GL_RGBA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative<GLhalf, 4> );
+ InsertD3D9FormatInfo(&map, GL_RGB16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative3To4<GLhalf, gl::Float16One> );
+ InsertD3D9FormatInfo(&map, GL_RG16F_EXT, D3DFMT_G16R16F, D3DFMT_G16R16F, LoadToNative<GLhalf, 2> );
+ InsertD3D9FormatInfo(&map, GL_R16F_EXT, D3DFMT_R16F, D3DFMT_R16F, LoadToNative<GLhalf, 1> );
+ InsertD3D9FormatInfo(&map, GL_ALPHA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadA16FToRGBA16F );
+ InsertD3D9FormatInfo(&map, GL_LUMINANCE16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadL16FToRGBA16F );
+ InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadLA16FToRGBA16F );
+
+ InsertD3D9FormatInfo(&map, GL_ALPHA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadA8ToBGRA8 );
+
+ InsertD3D9FormatInfo(&map, GL_RGB8_OES, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRGB8ToBGRX8 );
+ InsertD3D9FormatInfo(&map, GL_RGB565, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR5G6B5ToBGRA8 );
+ InsertD3D9FormatInfo(&map, GL_RGBA8_OES, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGBA8ToBGRA8 );
+ InsertD3D9FormatInfo(&map, GL_RGBA4, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGBA4ToBGRA8 );
+ InsertD3D9FormatInfo(&map, GL_RGB5_A1, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGB5A1ToBGRA8 );
+ InsertD3D9FormatInfo(&map, GL_R8_EXT, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR8ToBGRX8 );
+ InsertD3D9FormatInfo(&map, GL_RG8_EXT, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRG8ToBGRX8 );
+
+ InsertD3D9FormatInfo(&map, GL_BGRA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadToNative<GLubyte, 4> );
+ InsertD3D9FormatInfo(&map, GL_BGRA4_ANGLEX, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGRA4ToBGRA8 );
+ InsertD3D9FormatInfo(&map, GL_BGR5_A1_ANGLEX, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGR5A1ToBGRA8 );
+
+ InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 8> );
+ InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 8> );
+ InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, D3DFMT_DXT3, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 16> );
+ InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, D3DFMT_DXT5, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 16> );
+
+ // These formats require checking if the renderer supports D3DFMT_L8 or D3DFMT_A8L8 and
+ // then changing the format and loading function appropriately.
+ InsertD3D9FormatInfo(&map, GL_LUMINANCE8_EXT, D3DFMT_L8, D3DFMT_L8, LoadToNative<GLubyte, 1> );
+ InsertD3D9FormatInfo(&map, GL_LUMINANCE8_ALPHA8_EXT, D3DFMT_A8L8, D3DFMT_A8L8, LoadToNative<GLubyte, 2> );
+ // clang-format on
+
+ return map;
+}
+
+const TextureFormat &GetTextureFormatInfo(GLenum internalFormat)
+{
+ static const D3D9FormatMap formatMap = BuildD3D9FormatMap();
+ D3D9FormatMap::const_iterator iter = formatMap.find(internalFormat);
+ if (iter != formatMap.end())
+ {
+ return iter->second;
+ }
+ else
+ {
+ static const TextureFormat defaultInfo;
+ return defaultInfo;
+ }
+}
+
+static GLenum GetDeclTypeComponentType(D3DDECLTYPE declType)
+{
+ switch (declType)
+ {
+ case D3DDECLTYPE_FLOAT1: return GL_FLOAT;
+ case D3DDECLTYPE_FLOAT2: return GL_FLOAT;
+ case D3DDECLTYPE_FLOAT3: return GL_FLOAT;
+ case D3DDECLTYPE_FLOAT4: return GL_FLOAT;
+ case D3DDECLTYPE_UBYTE4: return GL_UNSIGNED_INT;
+ case D3DDECLTYPE_SHORT2: return GL_INT;
+ case D3DDECLTYPE_SHORT4: return GL_INT;
+ case D3DDECLTYPE_UBYTE4N: return GL_UNSIGNED_NORMALIZED;
+ case D3DDECLTYPE_SHORT4N: return GL_SIGNED_NORMALIZED;
+ case D3DDECLTYPE_USHORT4N: return GL_UNSIGNED_NORMALIZED;
+ case D3DDECLTYPE_SHORT2N: return GL_SIGNED_NORMALIZED;
+ case D3DDECLTYPE_USHORT2N: return GL_UNSIGNED_NORMALIZED;
+ default: UNREACHABLE(); return GL_NONE;
+ }
+}
+
+// Attribute format conversion
+enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 };
+
+struct TranslationDescription
+{
+ DWORD capsFlag;
+ VertexFormat preferredConversion;
+ VertexFormat fallbackConversion;
+};
+
+// Mapping from OpenGL-ES vertex attrib type to D3D decl type:
+//
+// BYTE SHORT (Cast)
+// BYTE-norm FLOAT (Normalize) (can't be exactly represented as SHORT-norm)
+// UNSIGNED_BYTE UBYTE4 (Identity) or SHORT (Cast)
+// UNSIGNED_BYTE-norm UBYTE4N (Identity) or FLOAT (Normalize)
+// SHORT SHORT (Identity)
+// SHORT-norm SHORT-norm (Identity) or FLOAT (Normalize)
+// UNSIGNED_SHORT FLOAT (Cast)
+// UNSIGNED_SHORT-norm USHORT-norm (Identity) or FLOAT (Normalize)
+// FIXED (not in WebGL) FLOAT (FixedToFloat)
+// FLOAT FLOAT (Identity)
+
+// GLToCType maps from GL type (as GLenum) to the C typedef.
+template <GLenum GLType> struct GLToCType { };
+
+template <> struct GLToCType<GL_BYTE> { typedef GLbyte type; };
+template <> struct GLToCType<GL_UNSIGNED_BYTE> { typedef GLubyte type; };
+template <> struct GLToCType<GL_SHORT> { typedef GLshort type; };
+template <> struct GLToCType<GL_UNSIGNED_SHORT> { typedef GLushort type; };
+template <> struct GLToCType<GL_FIXED> { typedef GLuint type; };
+template <> struct GLToCType<GL_FLOAT> { typedef GLfloat type; };
+
+// This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.)
+enum D3DVertexType
+{
+ D3DVT_FLOAT,
+ D3DVT_SHORT,
+ D3DVT_SHORT_NORM,
+ D3DVT_UBYTE,
+ D3DVT_UBYTE_NORM,
+ D3DVT_USHORT_NORM
+};
+
+// D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type.
+template <unsigned int D3DType> struct D3DToCType { };
+
+template <> struct D3DToCType<D3DVT_FLOAT> { typedef float type; };
+template <> struct D3DToCType<D3DVT_SHORT> { typedef short type; };
+template <> struct D3DToCType<D3DVT_SHORT_NORM> { typedef short type; };
+template <> struct D3DToCType<D3DVT_UBYTE> { typedef unsigned char type; };
+template <> struct D3DToCType<D3DVT_UBYTE_NORM> { typedef unsigned char type; };
+template <> struct D3DToCType<D3DVT_USHORT_NORM> { typedef unsigned short type; };
+
+// Encode the type/size combinations that D3D permits. For each type/size it expands to a widener that will provide the appropriate final size.
+template <unsigned int type, int size> struct WidenRule { };
+
+template <int size> struct WidenRule<D3DVT_FLOAT, size> : NoWiden<size> { };
+template <int size> struct WidenRule<D3DVT_SHORT, size> : WidenToEven<size> { };
+template <int size> struct WidenRule<D3DVT_SHORT_NORM, size> : WidenToEven<size> { };
+template <int size> struct WidenRule<D3DVT_UBYTE, size> : WidenToFour<size> { };
+template <int size> struct WidenRule<D3DVT_UBYTE_NORM, size> : WidenToFour<size> { };
+template <int size> struct WidenRule<D3DVT_USHORT_NORM, size> : WidenToEven<size> { };
+
+// VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D vertex type & size combination.
+template <unsigned int d3dtype, int size> struct VertexTypeFlags { };
+
+template <unsigned int _capflag, unsigned int _declflag>
+struct VertexTypeFlagsHelper
+{
+ enum { capflag = _capflag };
+ enum { declflag = _declflag };
+};
+
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 1> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> { };
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> { };
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 3> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> { };
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT2N, D3DDECLTYPE_SHORT2N> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT4N, D3DDECLTYPE_SHORT4N> { };
+template <> struct VertexTypeFlags<D3DVT_UBYTE, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4, D3DDECLTYPE_UBYTE4> { };
+template <> struct VertexTypeFlags<D3DVT_UBYTE_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4N, D3DDECLTYPE_UBYTE4N> { };
+template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT2N, D3DDECLTYPE_USHORT2N> { };
+template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT4N, D3DDECLTYPE_USHORT4N> { };
+
+
+// VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as D3DVertexType enums).
+template <GLenum GLtype, bool normalized> struct VertexTypeMapping { };
+
+template <D3DVertexType Preferred, D3DVertexType Fallback = Preferred>
+struct VertexTypeMappingBase
+{
+ enum { preferred = Preferred };
+ enum { fallback = Fallback };
+};
+
+template <> struct VertexTypeMapping<GL_BYTE, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Cast
+template <> struct VertexTypeMapping<GL_BYTE, true> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Normalize
+template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, false> : VertexTypeMappingBase<D3DVT_UBYTE, D3DVT_FLOAT> { }; // Identity, Cast
+template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, true> : VertexTypeMappingBase<D3DVT_UBYTE_NORM, D3DVT_FLOAT> { }; // Identity, Normalize
+template <> struct VertexTypeMapping<GL_SHORT, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Identity
+template <> struct VertexTypeMapping<GL_SHORT, true> : VertexTypeMappingBase<D3DVT_SHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize
+template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, false> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Cast
+template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, true> : VertexTypeMappingBase<D3DVT_USHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize
+template <bool normalized> struct VertexTypeMapping<GL_FIXED, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // FixedToFloat
+template <bool normalized> struct VertexTypeMapping<GL_FLOAT, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Identity
+
+
+// Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule (Cast, Normalize, Identity, FixedToFloat).
+// The conversion rules themselves are defined in vertexconversion.h.
+
+// Almost all cases are covered by Cast (including those that are actually Identity since Cast<T,T> knows it's an identity mapping).
+template <GLenum fromType, bool normalized, unsigned int toType>
+struct ConversionRule : Cast<typename GLToCType<fromType>::type, typename D3DToCType<toType>::type> { };
+
+// All conversions from normalized types to float use the Normalize operator.
+template <GLenum fromType> struct ConversionRule<fromType, true, D3DVT_FLOAT> : Normalize<typename GLToCType<fromType>::type> { };
+
+// Use a full specialization for this so that it preferentially matches ahead of the generic normalize-to-float rules.
+template <> struct ConversionRule<GL_FIXED, true, D3DVT_FLOAT> : FixedToFloat<GLint, 16> { };
+template <> struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : FixedToFloat<GLint, 16> { };
+
+// A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues (i.e. 0/1)
+// whether it is normalized or not.
+template <class T, bool normalized> struct DefaultVertexValuesStage2 { };
+
+template <class T> struct DefaultVertexValuesStage2<T, true> : NormalizedDefaultValues<T> { };
+template <class T> struct DefaultVertexValuesStage2<T, false> : SimpleDefaultValues<T> { };
+
+// Work out the default value rule for a D3D type (expressed as the C type) and
+template <class T, bool normalized> struct DefaultVertexValues : DefaultVertexValuesStage2<T, normalized> { };
+template <bool normalized> struct DefaultVertexValues<float, normalized> : SimpleDefaultValues<float> { };
+
+// Policy rules for use with Converter, to choose whether to use the preferred or fallback conversion.
+// The fallback conversion produces an output that all D3D9 devices must support.
+template <class T> struct UsePreferred { enum { type = T::preferred }; };
+template <class T> struct UseFallback { enum { type = T::fallback }; };
+
+// Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback conversion,
+// it provides all the members of the appropriate VertexDataConverter, the D3DCAPS9::DeclTypes flag in cap flag
+// and the D3DDECLTYPE member needed for the vertex declaration in declflag.
+template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule>
+struct Converter
+ : VertexDataConverter<
+ typename GLToCType<fromType>::type,
+ WidenRule<PreferenceRule<VertexTypeMapping<fromType, normalized>>::type, size>,
+ ConversionRule<fromType,
+ normalized,
+ PreferenceRule<VertexTypeMapping<fromType, normalized>>::type>,
+ DefaultVertexValues<typename D3DToCType<PreferenceRule<
+ VertexTypeMapping<fromType, normalized>>::type>::type,
+ normalized>>
+{
+private:
+ enum
+ {
+ d3dtype = PreferenceRule<VertexTypeMapping<fromType, normalized>>::type
+ };
+ enum
+ {
+ d3dsize = WidenRule<d3dtype, size>::finalWidth
+ };
+
+public:
+ enum { capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag };
+ enum { declflag = VertexTypeFlags<d3dtype, d3dsize>::declflag };
+};
+
+VertexFormat::VertexFormat()
+ : conversionType(VERTEX_CONVERT_NONE),
+ outputElementSize(0),
+ copyFunction(NULL),
+ nativeFormat(D3DDECLTYPE_UNUSED),
+ componentType(GL_NONE)
+{
+}
+
+// Initialize a TranslationInfo
+VertexFormat CreateVertexFormatInfo(bool identity, size_t elementSize, VertexCopyFunction copyFunc, D3DDECLTYPE nativeFormat)
+{
+ VertexFormat formatInfo;
+ formatInfo.conversionType = identity ? VERTEX_CONVERT_NONE : VERTEX_CONVERT_CPU;
+ formatInfo.outputElementSize = elementSize;
+ formatInfo.copyFunction = copyFunc;
+ formatInfo.nativeFormat = nativeFormat;
+ formatInfo.componentType = GetDeclTypeComponentType(nativeFormat);
+ return formatInfo;
+}
+
+#define TRANSLATION(type, norm, size, preferred) \
+ CreateVertexFormatInfo \
+ ( \
+ Converter<type, norm, size, preferred>::identity, \
+ Converter<type, norm, size, preferred>::finalSize, \
+ Converter<type, norm, size, preferred>::convertArray, \
+ static_cast<D3DDECLTYPE>(Converter<type, norm, size, preferred>::declflag) \
+ )
+
+#define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size) \
+ { \
+ Converter<type, norm, size, UsePreferred>::capflag, \
+ TRANSLATION(type, norm, size, UsePreferred), \
+ TRANSLATION(type, norm, size, UseFallback) \
+ }
+
+#define TRANSLATIONS_FOR_TYPE(type) \
+ { \
+ { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
+ { TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 4) }, \
+ }
+
+#define TRANSLATIONS_FOR_TYPE_NO_NORM(type) \
+ { \
+ { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
+ { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
+ }
+
+static inline unsigned int ComputeTypeIndex(GLenum type)
+{
+ switch (type)
+ {
+ case GL_BYTE: return 0;
+ case GL_UNSIGNED_BYTE: return 1;
+ case GL_SHORT: return 2;
+ case GL_UNSIGNED_SHORT: return 3;
+ case GL_FIXED: return 4;
+ case GL_FLOAT: return 5;
+
+ default: UNREACHABLE(); return 5;
+ }
+}
+
+const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, gl::VertexFormatType vertexFormatType)
+{
+ static bool initialized = false;
+ static DWORD initializedDeclTypes = 0;
+ static VertexFormat formatConverters[NUM_GL_VERTEX_ATTRIB_TYPES][2][4];
+ if (initializedDeclTypes != supportedDeclTypes)
+ {
+ const TranslationDescription translations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1]
+ {
+ TRANSLATIONS_FOR_TYPE(GL_BYTE),
+ TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE),
+ TRANSLATIONS_FOR_TYPE(GL_SHORT),
+ TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT),
+ TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FIXED),
+ TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FLOAT)
+ };
+ for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++)
+ {
+ for (unsigned int j = 0; j < 2; j++)
+ {
+ for (unsigned int k = 0; k < 4; k++)
+ {
+ if (translations[i][j][k].capsFlag == 0 || (supportedDeclTypes & translations[i][j][k].capsFlag) != 0)
+ {
+ formatConverters[i][j][k] = translations[i][j][k].preferredConversion;
+ }
+ else
+ {
+ formatConverters[i][j][k] = translations[i][j][k].fallbackConversion;
+ }
+ }
+ }
+ }
+ initialized = true;
+ initializedDeclTypes = supportedDeclTypes;
+ }
+
+ const gl::VertexFormat &vertexFormat = gl::GetVertexFormatFromType(vertexFormatType);
+
+ // Pure integer attributes only supported in ES3.0
+ ASSERT(!vertexFormat.pureInteger);
+ return formatConverters[ComputeTypeIndex(vertexFormat.type)][vertexFormat.normalized][vertexFormat.components - 1];
+}
+
+}
+
+}
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h
new file mode 100755
index 000000000..828252d33
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h
@@ -0,0 +1,94 @@
+//
+// Copyright (c) 2013-2014 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.
+//
+
+// formatutils9.h: Queries for GL image formats and their translations to D3D9
+// formats.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_FORMATUTILS9_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_FORMATUTILS9_H_
+
+#include <map>
+
+#include "common/platform.h"
+#include "libANGLE/angletypes.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/Format.h"
+#include "libANGLE/renderer/renderer_utils.h"
+#include "libANGLE/renderer/d3d/formatutilsD3D.h"
+
+namespace rx
+{
+
+class Renderer9;
+
+namespace d3d9
+{
+
+struct D3DFormat
+{
+ constexpr D3DFormat();
+ constexpr D3DFormat(GLuint pixelBytes,
+ GLuint blockWidth,
+ GLuint blockHeight,
+ GLuint redBits,
+ GLuint greenBits,
+ GLuint blueBits,
+ GLuint alphaBits,
+ GLuint luminanceBits,
+ GLuint depthBits,
+ GLuint stencilBits,
+ angle::Format::ID formatID);
+
+ const angle::Format &info() const { return angle::Format::Get(formatID); }
+
+ GLuint pixelBytes;
+ GLuint blockWidth;
+ GLuint blockHeight;
+
+ GLuint redBits;
+ GLuint greenBits;
+ GLuint blueBits;
+ GLuint alphaBits;
+ GLuint luminanceBits;
+
+ GLuint depthBits;
+ GLuint stencilBits;
+
+ angle::Format::ID formatID;
+};
+
+const D3DFormat &GetD3DFormatInfo(D3DFORMAT format);
+
+struct VertexFormat
+{
+ VertexFormat();
+
+ VertexConversionType conversionType;
+ size_t outputElementSize;
+ VertexCopyFunction copyFunction;
+ D3DDECLTYPE nativeFormat;
+ GLenum componentType;
+};
+const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, gl::VertexFormatType vertexFormatType);
+
+struct TextureFormat
+{
+ TextureFormat();
+
+ D3DFORMAT texFormat;
+ D3DFORMAT renderFormat;
+
+ InitializeTextureDataFunction dataInitializerFunction;
+
+ LoadImageFunction loadFunction;
+};
+const TextureFormat &GetTextureFormatInfo(GLenum internalFormat);
+
+}
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_FORMATUTILS9_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp
new file mode 100755
index 000000000..a6e1f239d
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp
@@ -0,0 +1,659 @@
+//
+// Copyright (c) 2002-2014 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.
+//
+
+// renderer9_utils.cpp: Conversion functions and other utility routines
+// specific to the D3D9 renderer.
+
+#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
+
+#include "common/mathutil.h"
+#include "common/debug.h"
+
+#include "libANGLE/formatutils.h"
+#include "libANGLE/Framebuffer.h"
+#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
+#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
+#include "libANGLE/renderer/d3d/FramebufferD3D.h"
+#include "libANGLE/renderer/d3d/WorkaroundsD3D.h"
+#include "libANGLE/renderer/driver_utils.h"
+
+#include "third_party/systeminfo/SystemInfo.h"
+
+namespace rx
+{
+
+namespace gl_d3d9
+{
+
+D3DCMPFUNC ConvertComparison(GLenum comparison)
+{
+ D3DCMPFUNC d3dComp = D3DCMP_ALWAYS;
+ switch (comparison)
+ {
+ case GL_NEVER: d3dComp = D3DCMP_NEVER; break;
+ case GL_ALWAYS: d3dComp = D3DCMP_ALWAYS; break;
+ case GL_LESS: d3dComp = D3DCMP_LESS; break;
+ case GL_LEQUAL: d3dComp = D3DCMP_LESSEQUAL; break;
+ case GL_EQUAL: d3dComp = D3DCMP_EQUAL; break;
+ case GL_GREATER: d3dComp = D3DCMP_GREATER; break;
+ case GL_GEQUAL: d3dComp = D3DCMP_GREATEREQUAL; break;
+ case GL_NOTEQUAL: d3dComp = D3DCMP_NOTEQUAL; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dComp;
+}
+
+D3DCOLOR ConvertColor(gl::ColorF color)
+{
+ return D3DCOLOR_RGBA(gl::unorm<8>(color.red),
+ gl::unorm<8>(color.green),
+ gl::unorm<8>(color.blue),
+ gl::unorm<8>(color.alpha));
+}
+
+D3DBLEND ConvertBlendFunc(GLenum blend)
+{
+ D3DBLEND d3dBlend = D3DBLEND_ZERO;
+
+ switch (blend)
+ {
+ case GL_ZERO: d3dBlend = D3DBLEND_ZERO; break;
+ case GL_ONE: d3dBlend = D3DBLEND_ONE; break;
+ case GL_SRC_COLOR: d3dBlend = D3DBLEND_SRCCOLOR; break;
+ case GL_ONE_MINUS_SRC_COLOR: d3dBlend = D3DBLEND_INVSRCCOLOR; break;
+ case GL_DST_COLOR: d3dBlend = D3DBLEND_DESTCOLOR; break;
+ case GL_ONE_MINUS_DST_COLOR: d3dBlend = D3DBLEND_INVDESTCOLOR; break;
+ case GL_SRC_ALPHA: d3dBlend = D3DBLEND_SRCALPHA; break;
+ case GL_ONE_MINUS_SRC_ALPHA: d3dBlend = D3DBLEND_INVSRCALPHA; break;
+ case GL_DST_ALPHA: d3dBlend = D3DBLEND_DESTALPHA; break;
+ case GL_ONE_MINUS_DST_ALPHA: d3dBlend = D3DBLEND_INVDESTALPHA; break;
+ case GL_CONSTANT_COLOR: d3dBlend = D3DBLEND_BLENDFACTOR; break;
+ case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3DBLEND_INVBLENDFACTOR; break;
+ case GL_CONSTANT_ALPHA: d3dBlend = D3DBLEND_BLENDFACTOR; break;
+ case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3DBLEND_INVBLENDFACTOR; break;
+ case GL_SRC_ALPHA_SATURATE: d3dBlend = D3DBLEND_SRCALPHASAT; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dBlend;
+}
+
+D3DBLENDOP ConvertBlendOp(GLenum blendOp)
+{
+ D3DBLENDOP d3dBlendOp = D3DBLENDOP_ADD;
+
+ switch (blendOp)
+ {
+ case GL_FUNC_ADD: d3dBlendOp = D3DBLENDOP_ADD; break;
+ case GL_FUNC_SUBTRACT: d3dBlendOp = D3DBLENDOP_SUBTRACT; break;
+ case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3DBLENDOP_REVSUBTRACT; break;
+ case GL_MIN_EXT: d3dBlendOp = D3DBLENDOP_MIN; break;
+ case GL_MAX_EXT: d3dBlendOp = D3DBLENDOP_MAX; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dBlendOp;
+}
+
+D3DSTENCILOP ConvertStencilOp(GLenum stencilOp)
+{
+ D3DSTENCILOP d3dStencilOp = D3DSTENCILOP_KEEP;
+
+ switch (stencilOp)
+ {
+ case GL_ZERO: d3dStencilOp = D3DSTENCILOP_ZERO; break;
+ case GL_KEEP: d3dStencilOp = D3DSTENCILOP_KEEP; break;
+ case GL_REPLACE: d3dStencilOp = D3DSTENCILOP_REPLACE; break;
+ case GL_INCR: d3dStencilOp = D3DSTENCILOP_INCRSAT; break;
+ case GL_DECR: d3dStencilOp = D3DSTENCILOP_DECRSAT; break;
+ case GL_INVERT: d3dStencilOp = D3DSTENCILOP_INVERT; break;
+ case GL_INCR_WRAP: d3dStencilOp = D3DSTENCILOP_INCR; break;
+ case GL_DECR_WRAP: d3dStencilOp = D3DSTENCILOP_DECR; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dStencilOp;
+}
+
+D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap)
+{
+ D3DTEXTUREADDRESS d3dWrap = D3DTADDRESS_WRAP;
+
+ switch (wrap)
+ {
+ case GL_REPEAT: d3dWrap = D3DTADDRESS_WRAP; break;
+ case GL_CLAMP_TO_EDGE: d3dWrap = D3DTADDRESS_CLAMP; break;
+ case GL_MIRRORED_REPEAT: d3dWrap = D3DTADDRESS_MIRROR; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dWrap;
+}
+
+D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace)
+{
+ D3DCULL cull = D3DCULL_CCW;
+ switch (cullFace)
+ {
+ case GL_FRONT:
+ cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW);
+ break;
+ case GL_BACK:
+ cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW);
+ break;
+ case GL_FRONT_AND_BACK:
+ cull = D3DCULL_NONE; // culling will be handled during draw
+ break;
+ default: UNREACHABLE();
+ }
+
+ return cull;
+}
+
+D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace)
+{
+ D3DCUBEMAP_FACES face = D3DCUBEMAP_FACE_POSITIVE_X;
+
+ switch (cubeFace)
+ {
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ face = D3DCUBEMAP_FACE_POSITIVE_X;
+ break;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ face = D3DCUBEMAP_FACE_NEGATIVE_X;
+ break;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ face = D3DCUBEMAP_FACE_POSITIVE_Y;
+ break;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ face = D3DCUBEMAP_FACE_NEGATIVE_Y;
+ break;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ face = D3DCUBEMAP_FACE_POSITIVE_Z;
+ break;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ face = D3DCUBEMAP_FACE_NEGATIVE_Z;
+ break;
+ default: UNREACHABLE();
+ }
+
+ return face;
+}
+
+DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha)
+{
+ return (red ? D3DCOLORWRITEENABLE_RED : 0) |
+ (green ? D3DCOLORWRITEENABLE_GREEN : 0) |
+ (blue ? D3DCOLORWRITEENABLE_BLUE : 0) |
+ (alpha ? D3DCOLORWRITEENABLE_ALPHA : 0);
+}
+
+D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy)
+{
+ if (maxAnisotropy > 1.0f)
+ {
+ return D3DTEXF_ANISOTROPIC;
+ }
+
+ D3DTEXTUREFILTERTYPE d3dMagFilter = D3DTEXF_POINT;
+ switch (magFilter)
+ {
+ case GL_NEAREST: d3dMagFilter = D3DTEXF_POINT; break;
+ case GL_LINEAR: d3dMagFilter = D3DTEXF_LINEAR; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dMagFilter;
+}
+
+void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter,
+ float *d3dLodBias, float maxAnisotropy, size_t baseLevel)
+{
+ switch (minFilter)
+ {
+ case GL_NEAREST:
+ *d3dMinFilter = D3DTEXF_POINT;
+ *d3dMipFilter = D3DTEXF_NONE;
+ break;
+ case GL_LINEAR:
+ *d3dMinFilter = D3DTEXF_LINEAR;
+ *d3dMipFilter = D3DTEXF_NONE;
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ *d3dMinFilter = D3DTEXF_POINT;
+ *d3dMipFilter = D3DTEXF_POINT;
+ break;
+ case GL_LINEAR_MIPMAP_NEAREST:
+ *d3dMinFilter = D3DTEXF_LINEAR;
+ *d3dMipFilter = D3DTEXF_POINT;
+ break;
+ case GL_NEAREST_MIPMAP_LINEAR:
+ *d3dMinFilter = D3DTEXF_POINT;
+ *d3dMipFilter = D3DTEXF_LINEAR;
+ break;
+ case GL_LINEAR_MIPMAP_LINEAR:
+ *d3dMinFilter = D3DTEXF_LINEAR;
+ *d3dMipFilter = D3DTEXF_LINEAR;
+ break;
+ default:
+ *d3dMinFilter = D3DTEXF_POINT;
+ *d3dMipFilter = D3DTEXF_NONE;
+ UNREACHABLE();
+ }
+
+ // Disabling mipmapping will always sample from level 0 of the texture. It is possible to work
+ // around this by modifying D3DSAMP_MAXMIPLEVEL to force a specific mip level to become the
+ // lowest sampled mip level and using a large negative value for D3DSAMP_MIPMAPLODBIAS to
+ // ensure that only the base mip level is sampled.
+ if (baseLevel > 0 && *d3dMipFilter == D3DTEXF_NONE)
+ {
+ *d3dMipFilter = D3DTEXF_POINT;
+ *d3dLodBias = -static_cast<float>(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
+ }
+ else
+ {
+ *d3dLodBias = 0.0f;
+ }
+
+ if (maxAnisotropy > 1.0f)
+ {
+ *d3dMinFilter = D3DTEXF_ANISOTROPIC;
+ }
+}
+
+D3DQUERYTYPE ConvertQueryType(GLenum queryType)
+{
+ switch (queryType)
+ {
+ case GL_ANY_SAMPLES_PASSED_EXT:
+ case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
+ return D3DQUERYTYPE_OCCLUSION;
+ case GL_COMMANDS_COMPLETED_CHROMIUM:
+ return D3DQUERYTYPE_EVENT;
+ default:
+ UNREACHABLE();
+ return static_cast<D3DQUERYTYPE>(0);
+ }
+}
+
+D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples)
+{
+ return (samples > 1) ? static_cast<D3DMULTISAMPLE_TYPE>(samples) : D3DMULTISAMPLE_NONE;
+}
+
+}
+
+namespace d3d9_gl
+{
+
+unsigned int GetReservedVertexUniformVectors()
+{
+ return 3; // dx_ViewCoords, dx_ViewAdjust and dx_DepthRange.
+}
+
+unsigned int GetReservedFragmentUniformVectors()
+{
+ return 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange.
+}
+
+GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type)
+{
+ return (type != D3DMULTISAMPLE_NONMASKABLE) ? type : 0;
+}
+
+bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format)
+{
+ GLenum internalFormat = d3d9::GetD3DFormatInfo(d3dformat).info().glInternalFormat;
+ GLenum convertedFormat = gl::GetInternalFormatInfo(internalFormat).format;
+ return convertedFormat == format;
+}
+
+static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, IDirect3D9 *d3d9, D3DDEVTYPE deviceType,
+ UINT adapter, D3DFORMAT adapterFormat)
+{
+ gl::TextureCaps textureCaps;
+
+ const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalFormat);
+ const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
+
+ if (d3dFormatInfo.texFormat != D3DFMT_UNKNOWN)
+ {
+ if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
+ {
+ textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat));
+ }
+ else
+ {
+ textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)) &&
+ SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_CUBETEXTURE, d3dFormatInfo.texFormat));
+ }
+
+ textureCaps.filterable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat));
+ }
+
+ if (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN)
+ {
+ textureCaps.renderable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat));
+
+ if ((formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) && !textureCaps.renderable)
+ {
+ textureCaps.renderable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat));
+ }
+
+ textureCaps.sampleCounts.insert(1);
+ for (unsigned int i = D3DMULTISAMPLE_2_SAMPLES; i <= D3DMULTISAMPLE_16_SAMPLES; i++)
+ {
+ D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_TYPE(i);
+
+ HRESULT result = d3d9->CheckDeviceMultiSampleType(adapter, deviceType, d3dFormatInfo.renderFormat, TRUE, multisampleType, NULL);
+ if (SUCCEEDED(result))
+ {
+ textureCaps.sampleCounts.insert(i);
+ }
+ }
+ }
+
+ return textureCaps;
+}
+
+void GenerateCaps(IDirect3D9 *d3d9,
+ IDirect3DDevice9 *device,
+ D3DDEVTYPE deviceType,
+ UINT adapter,
+ gl::Caps *caps,
+ gl::TextureCapsMap *textureCapsMap,
+ gl::Extensions *extensions,
+ gl::Limitations *limitations)
+{
+ D3DCAPS9 deviceCaps;
+ if (FAILED(d3d9->GetDeviceCaps(adapter, deviceType, &deviceCaps)))
+ {
+ // Can't continue with out device caps
+ return;
+ }
+
+ D3DDISPLAYMODE currentDisplayMode;
+ d3d9->GetAdapterDisplayMode(adapter, &currentDisplayMode);
+
+ GLuint maxSamples = 0;
+ const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats();
+ for (gl::FormatSet::const_iterator internalFormat = allFormats.begin(); internalFormat != allFormats.end(); ++internalFormat)
+ {
+ gl::TextureCaps textureCaps = GenerateTextureFormatCaps(*internalFormat, d3d9, deviceType, adapter,
+ currentDisplayMode.Format);
+ textureCapsMap->insert(*internalFormat, textureCaps);
+
+ maxSamples = std::max(maxSamples, textureCaps.getMaxSamples());
+
+ if (gl::GetInternalFormatInfo(*internalFormat).compressed)
+ {
+ caps->compressedTextureFormats.push_back(*internalFormat);
+ }
+ }
+
+ // GL core feature limits
+ caps->maxElementIndex = static_cast<GLint64>(std::numeric_limits<unsigned int>::max());
+
+ // 3D textures are unimplemented in D3D9
+ caps->max3DTextureSize = 1;
+
+ // Only one limit in GL, use the minimum dimension
+ caps->max2DTextureSize = std::min(deviceCaps.MaxTextureWidth, deviceCaps.MaxTextureHeight);
+
+ // D3D treats cube maps as a special case of 2D textures
+ caps->maxCubeMapTextureSize = caps->max2DTextureSize;
+
+ // Array textures are not available in D3D9
+ caps->maxArrayTextureLayers = 1;
+
+ // ES3-only feature
+ caps->maxLODBias = 0.0f;
+
+ // No specific limits on render target size, maximum 2D texture size is equivalent
+ caps->maxRenderbufferSize = caps->max2DTextureSize;
+
+ // Draw buffers are not supported in D3D9
+ caps->maxDrawBuffers = 1;
+ caps->maxColorAttachments = 1;
+
+ // No specific limits on viewport size, maximum 2D texture size is equivalent
+ caps->maxViewportWidth = caps->max2DTextureSize;
+ caps->maxViewportHeight = caps->maxViewportWidth;
+
+ // Point size is clamped to 1.0f when the shader model is less than 3
+ caps->minAliasedPointSize = 1.0f;
+ caps->maxAliasedPointSize = ((D3DSHADER_VERSION_MAJOR(deviceCaps.PixelShaderVersion) >= 3) ? deviceCaps.MaxPointSize : 1.0f);
+
+ // Wide lines not supported
+ caps->minAliasedLineWidth = 1.0f;
+ caps->maxAliasedLineWidth = 1.0f;
+
+ // Primitive count limits (unused in ES2)
+ caps->maxElementsIndices = 0;
+ caps->maxElementsVertices = 0;
+
+ // Program and shader binary formats (no supported shader binary formats)
+ caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE);
+
+ caps->vertexHighpFloat.setIEEEFloat();
+ caps->vertexMediumpFloat.setIEEEFloat();
+ caps->vertexLowpFloat.setIEEEFloat();
+ caps->fragmentHighpFloat.setIEEEFloat();
+ caps->fragmentMediumpFloat.setIEEEFloat();
+ caps->fragmentLowpFloat.setIEEEFloat();
+
+ // Some (most) hardware only supports single-precision floating-point numbers,
+ // which can accurately represent integers up to +/-16777216
+ caps->vertexHighpInt.setSimulatedInt(24);
+ caps->vertexMediumpInt.setSimulatedInt(24);
+ caps->vertexLowpInt.setSimulatedInt(24);
+ caps->fragmentHighpInt.setSimulatedInt(24);
+ caps->fragmentMediumpInt.setSimulatedInt(24);
+ caps->fragmentLowpInt.setSimulatedInt(24);
+
+ // WaitSync is ES3-only, set to zero
+ caps->maxServerWaitTimeout = 0;
+
+ // Vertex shader limits
+ caps->maxVertexAttributes = 16;
+
+ const size_t MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256;
+ caps->maxVertexUniformVectors =
+ MAX_VERTEX_CONSTANT_VECTORS_D3D9 - GetReservedVertexUniformVectors();
+ caps->maxVertexUniformComponents = caps->maxVertexUniformVectors * 4;
+
+ caps->maxVertexUniformBlocks = 0;
+
+ // SM3 only supports 11 output variables, with a special 12th register for PSIZE.
+ const size_t MAX_VERTEX_OUTPUT_VECTORS_SM3 = 9;
+ const size_t MAX_VERTEX_OUTPUT_VECTORS_SM2 = 7;
+ caps->maxVertexOutputComponents = ((deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0)) ? MAX_VERTEX_OUTPUT_VECTORS_SM3
+ : MAX_VERTEX_OUTPUT_VECTORS_SM2) * 4;
+
+ // Only Direct3D 10 ready devices support all the necessary vertex texture formats.
+ // We test this using D3D9 by checking support for the R16F format.
+ if (deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0) &&
+ SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, currentDisplayMode.Format,
+ D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F)))
+ {
+ const size_t MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4;
+ caps->maxVertexTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS_VTF_SM3;
+ }
+ else
+ {
+ caps->maxVertexTextureImageUnits = 0;
+ }
+
+ // Fragment shader limits
+ const size_t MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224;
+ const size_t MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32;
+ caps->maxFragmentUniformVectors =
+ ((deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) ? MAX_PIXEL_CONSTANT_VECTORS_SM3
+ : MAX_PIXEL_CONSTANT_VECTORS_SM2) -
+ GetReservedFragmentUniformVectors();
+ caps->maxFragmentUniformComponents = caps->maxFragmentUniformVectors * 4;
+ caps->maxFragmentUniformBlocks = 0;
+ caps->maxFragmentInputComponents = caps->maxVertexOutputComponents;
+ caps->maxTextureImageUnits = 16;
+ caps->minProgramTexelOffset = 0;
+ caps->maxProgramTexelOffset = 0;
+
+ // Aggregate shader limits (unused in ES2)
+ caps->maxUniformBufferBindings = 0;
+ caps->maxUniformBlockSize = 0;
+ caps->uniformBufferOffsetAlignment = 0;
+ caps->maxCombinedUniformBlocks = 0;
+ caps->maxCombinedVertexUniformComponents = 0;
+ caps->maxCombinedFragmentUniformComponents = 0;
+ caps->maxVaryingComponents = 0;
+
+ // Aggregate shader limits
+ caps->maxVaryingVectors = caps->maxVertexOutputComponents / 4;
+ caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits;
+
+ // Transform feedback limits
+ caps->maxTransformFeedbackInterleavedComponents = 0;
+ caps->maxTransformFeedbackSeparateAttributes = 0;
+ caps->maxTransformFeedbackSeparateComponents = 0;
+
+ // Multisample limits
+ caps->maxSamples = maxSamples;
+
+ // GL extension support
+ extensions->setTextureExtensionSupport(*textureCapsMap);
+ extensions->elementIndexUint = deviceCaps.MaxVertexIndex >= (1 << 16);
+ extensions->getProgramBinary = true;
+ extensions->rgb8rgba8 = true;
+ extensions->readFormatBGRA = true;
+ extensions->pixelBufferObject = false;
+ extensions->mapBuffer = false;
+ extensions->mapBufferRange = false;
+
+ // textureRG is emulated and not performant.
+ extensions->textureRG = false;
+
+ D3DADAPTER_IDENTIFIER9 adapterId = {};
+ if (SUCCEEDED(d3d9->GetAdapterIdentifier(adapter, 0, &adapterId)))
+ {
+ // ATI cards on XP have problems with non-power-of-two textures.
+ extensions->textureNPOT = !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) &&
+ !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) &&
+ !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) &&
+ !(!isWindowsVistaOrGreater() && IsAMD(adapterId.VendorId));
+
+ // Disable depth texture support on AMD cards (See ANGLE issue 839)
+ if (IsAMD(adapterId.VendorId))
+ {
+ extensions->depthTextures = false;
+ }
+ }
+ else
+ {
+ extensions->textureNPOT = false;
+ }
+
+ extensions->drawBuffers = false;
+ extensions->textureStorage = true;
+
+ // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per the spec
+ extensions->textureFilterAnisotropic = (deviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && deviceCaps.MaxAnisotropy >= 2;
+ extensions->maxTextureAnisotropy = static_cast<GLfloat>(deviceCaps.MaxAnisotropy);
+
+ // Check occlusion query support by trying to create one
+ IDirect3DQuery9 *occlusionQuery = NULL;
+ extensions->occlusionQueryBoolean = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery;
+ SafeRelease(occlusionQuery);
+
+ // Check event query support by trying to create one
+ IDirect3DQuery9 *eventQuery = NULL;
+ extensions->fence = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery;
+ SafeRelease(eventQuery);
+
+ extensions->timerQuery = false; // Unimplemented
+ extensions->disjointTimerQuery = false;
+ extensions->robustness = true;
+ extensions->blendMinMax = true;
+ extensions->framebufferBlit = true;
+ extensions->framebufferMultisample = true;
+ extensions->instancedArrays = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
+ extensions->packReverseRowOrder = true;
+ extensions->standardDerivatives = (deviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0;
+ extensions->shaderTextureLOD = true;
+ extensions->fragDepth = true;
+ extensions->textureUsage = true;
+ extensions->translatedShaderSource = true;
+ extensions->fboRenderMipmap = false;
+ extensions->discardFramebuffer = false; // It would be valid to set this to true, since glDiscardFramebufferEXT is just a hint
+ extensions->colorBufferFloat = false;
+ extensions->debugMarker = true;
+ extensions->eglImage = true;
+ extensions->eglImageExternal = true;
+ extensions->unpackSubimage = true;
+ extensions->packSubimage = true;
+ extensions->syncQuery = extensions->fence;
+
+ // D3D9 has no concept of separate masks and refs for front and back faces in the depth stencil
+ // state.
+ limitations->noSeparateStencilRefsAndMasks = true;
+
+ // D3D9 shader models have limited support for looping, so the Appendix A
+ // index/loop limitations are necessary. Workarounds that are needed to
+ // support dynamic indexing of vectors on HLSL also don't work on D3D9.
+ limitations->shadersRequireIndexedLoopValidation = true;
+
+ // D3D9 cannot support constant color and alpha blend funcs together
+ limitations->noSimultaneousConstantColorAndAlphaBlendFunc = true;
+}
+
+}
+
+namespace d3d9
+{
+
+GLuint ComputeBlockSize(D3DFORMAT format, GLuint width, GLuint height)
+{
+ const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format);
+ GLuint numBlocksWide = (width + d3dFormatInfo.blockWidth - 1) / d3dFormatInfo.blockWidth;
+ GLuint numBlocksHight = (height + d3dFormatInfo.blockHeight - 1) / d3dFormatInfo.blockHeight;
+ return (d3dFormatInfo.pixelBytes * numBlocksWide * numBlocksHight);
+}
+
+void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset)
+{
+ const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format);
+
+ int upsampleCount = 0;
+ // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already.
+ if (isImage || *requestWidth < static_cast<GLsizei>(d3dFormatInfo.blockWidth) ||
+ *requestHeight < static_cast<GLsizei>(d3dFormatInfo.blockHeight))
+ {
+ while (*requestWidth % d3dFormatInfo.blockWidth != 0 || *requestHeight % d3dFormatInfo.blockHeight != 0)
+ {
+ *requestWidth <<= 1;
+ *requestHeight <<= 1;
+ upsampleCount++;
+ }
+ }
+ *levelOffset = upsampleCount;
+}
+
+WorkaroundsD3D GenerateWorkarounds()
+{
+ WorkaroundsD3D workarounds;
+ workarounds.mrtPerfWorkaround = true;
+ workarounds.setDataFasterThanImageUpload = false;
+ workarounds.useInstancedPointSpriteEmulation = false;
+
+ // TODO(jmadill): Disable workaround when we have a fixed compiler DLL.
+ workarounds.expandIntegerPowExpressions = true;
+
+ return workarounds;
+}
+
+} // namespace d3d9
+
+} // namespace rx
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h
new file mode 100755
index 000000000..ff6d55fd5
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h
@@ -0,0 +1,95 @@
+//
+// Copyright (c) 2002-2014 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.
+//
+
+// renderer9_utils.h: Conversion functions and other utility routines
+// specific to the D3D9 renderer
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_
+
+#include "common/Color.h"
+#include "libANGLE/Caps.h"
+#include "libANGLE/Error.h"
+
+namespace gl
+{
+class FramebufferAttachment;
+}
+
+namespace rx
+{
+class RenderTarget9;
+struct WorkaroundsD3D;
+
+namespace gl_d3d9
+{
+
+D3DCMPFUNC ConvertComparison(GLenum comparison);
+D3DCOLOR ConvertColor(gl::ColorF color);
+D3DBLEND ConvertBlendFunc(GLenum blend);
+D3DBLENDOP ConvertBlendOp(GLenum blendOp);
+D3DSTENCILOP ConvertStencilOp(GLenum stencilOp);
+D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap);
+D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace);
+D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace);
+DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha);
+D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy);
+void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter,
+ float *d3dLodBias, float maxAnisotropy, size_t baseLevel);
+D3DQUERYTYPE ConvertQueryType(GLenum queryType);
+
+D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples);
+
+}
+
+namespace d3d9_gl
+{
+
+unsigned int GetReservedVertexUniformVectors();
+
+unsigned int GetReservedFragmentUniformVectors();
+
+GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type);
+
+bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format);
+
+void GenerateCaps(IDirect3D9 *d3d9,
+ IDirect3DDevice9 *device,
+ D3DDEVTYPE deviceType,
+ UINT adapter,
+ gl::Caps *caps,
+ gl::TextureCapsMap *textureCapsMap,
+ gl::Extensions *extensions,
+ gl::Limitations *limitations);
+}
+
+namespace d3d9
+{
+
+GLuint ComputeBlockSize(D3DFORMAT format, GLuint width, GLuint height);
+
+void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset);
+
+inline bool isDeviceLostError(HRESULT errorCode)
+{
+ switch (errorCode)
+ {
+ case D3DERR_DRIVERINTERNALERROR:
+ case D3DERR_DEVICELOST:
+ case D3DERR_DEVICEHUNG:
+ case D3DERR_DEVICEREMOVED:
+ return true;
+ default:
+ return false;
+ }
+}
+
+WorkaroundsD3D GenerateWorkarounds();
+}
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps
new file mode 100755
index 000000000..dc357d0fa
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2012 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.
+//
+
+sampler2D tex : s0;
+
+uniform float4 mult : c0;
+uniform float4 add : c1;
+
+// Passthrough Pixel Shader
+// Outputs texture 0 sampled at texcoord 0.
+float4 passthroughps(float4 texcoord : TEXCOORD0) : COLOR
+{
+ return tex2D(tex, texcoord.xy);
+};
+
+// Luminance Conversion Pixel Shader
+// Performs a mad operation using the LA data from the texture with mult.xw and add.xw.
+// Returns data in the form of llla
+float4 luminanceps(float4 texcoord : TEXCOORD0) : COLOR
+{
+ return (tex2D(tex, texcoord.xy).xw * mult.xw + add.xw).xxxy;
+};
+
+// RGB/A Component Mask Pixel Shader
+// Performs a mad operation using the texture's RGBA data with mult.xyzw and add.xyzw.
+// Returns data in the form of rgba
+float4 componentmaskps(float4 texcoord : TEXCOORD0) : COLOR
+{
+ return tex2D(tex, texcoord.xy) * mult + add;
+};
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs
new file mode 100755
index 000000000..3a36980b9
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2012 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.
+//
+
+struct VS_OUTPUT
+{
+ float4 position : POSITION;
+ float4 texcoord : TEXCOORD0;
+};
+
+uniform float4 halfPixelSize : c0;
+
+// Standard Vertex Shader
+// Input 0 is the homogenous position.
+// Outputs the homogenous position as-is.
+// Outputs a tex coord with (0,0) in the upper-left corner of the screen and (1,1) in the bottom right.
+// C0.X must be negative half-pixel width, C0.Y must be half-pixel height. C0.ZW must be 0.
+VS_OUTPUT standardvs(in float4 position : POSITION)
+{
+ VS_OUTPUT Out;
+
+ Out.position = position + halfPixelSize;
+ Out.texcoord = position * float4(0.5, -0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0);
+
+ return Out;
+};
+
+// Flip Y Vertex Shader
+// Input 0 is the homogenous position.
+// Outputs the homogenous position as-is.
+// Outputs a tex coord with (0,1) in the upper-left corner of the screen and (1,0) in the bottom right.
+// C0.XY must be the half-pixel width and height. C0.ZW must be 0.
+VS_OUTPUT flipyvs(in float4 position : POSITION)
+{
+ VS_OUTPUT Out;
+
+ Out.position = position + halfPixelSize;
+ Out.texcoord = position * float4(0.5, 0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0);
+
+ return Out;
+};
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h
new file mode 100755
index 000000000..24482d755
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h
@@ -0,0 +1,84 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+//
+// Parameters:
+//
+// float4 add;
+// float4 mult;
+// sampler2D tex;
+//
+//
+// Registers:
+//
+// Name Reg Size
+// ------------ ----- ----
+// mult c0 1
+// add c1 1
+// tex s0 1
+//
+
+ ps_2_0
+ dcl t0.xy
+ dcl_2d s0
+ texld r0, t0, s0
+ mov r1, c0
+ mad r0, r0, r1, c1
+ mov oC0, r0
+
+// approximately 4 instruction slots used (1 texture, 3 arithmetic)
+#endif
+
+const BYTE g_ps20_componentmaskps[] =
+{
+ 0, 2, 255, 255, 254, 255,
+ 50, 0, 67, 84, 65, 66,
+ 28, 0, 0, 0, 143, 0,
+ 0, 0, 0, 2, 255, 255,
+ 3, 0, 0, 0, 28, 0,
+ 0, 0, 0, 1, 0, 0,
+ 136, 0, 0, 0, 88, 0,
+ 0, 0, 2, 0, 1, 0,
+ 1, 0, 0, 0, 92, 0,
+ 0, 0, 0, 0, 0, 0,
+ 108, 0, 0, 0, 2, 0,
+ 0, 0, 1, 0, 0, 0,
+ 92, 0, 0, 0, 0, 0,
+ 0, 0, 113, 0, 0, 0,
+ 3, 0, 0, 0, 1, 0,
+ 0, 0, 120, 0, 0, 0,
+ 0, 0, 0, 0, 97, 100,
+ 100, 0, 1, 0, 3, 0,
+ 1, 0, 4, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 109, 117, 108, 116, 0, 116,
+ 101, 120, 0, 171, 171, 171,
+ 4, 0, 12, 0, 1, 0,
+ 1, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 112, 115,
+ 95, 50, 95, 48, 0, 77,
+ 105, 99, 114, 111, 115, 111,
+ 102, 116, 32, 40, 82, 41,
+ 32, 72, 76, 83, 76, 32,
+ 83, 104, 97, 100, 101, 114,
+ 32, 67, 111, 109, 112, 105,
+ 108, 101, 114, 32, 54, 46,
+ 51, 46, 57, 54, 48, 48,
+ 46, 49, 54, 51, 56, 52,
+ 0, 171, 171, 171, 31, 0,
+ 0, 2, 0, 0, 0, 128,
+ 0, 0, 3, 176, 31, 0,
+ 0, 2, 0, 0, 0, 144,
+ 0, 8, 15, 160, 66, 0,
+ 0, 3, 0, 0, 15, 128,
+ 0, 0, 228, 176, 0, 8,
+ 228, 160, 1, 0, 0, 2,
+ 1, 0, 15, 128, 0, 0,
+ 228, 160, 4, 0, 0, 4,
+ 0, 0, 15, 128, 0, 0,
+ 228, 128, 1, 0, 228, 128,
+ 1, 0, 228, 160, 1, 0,
+ 0, 2, 0, 8, 15, 128,
+ 0, 0, 228, 128, 255, 255,
+ 0, 0
+};
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/flipyvs.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/flipyvs.h
new file mode 100755
index 000000000..5eb513132
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/flipyvs.h
@@ -0,0 +1,66 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+//
+// Parameters:
+//
+// float4 halfPixelSize;
+//
+//
+// Registers:
+//
+// Name Reg Size
+// ------------- ----- ----
+// halfPixelSize c0 1
+//
+
+ vs_2_0
+ def c1, 0.5, 1, 0, 0
+ dcl_position v0
+ add oPos, v0, c0
+ mad oT0, v0, c1.xxyy, c1.xxzz
+
+// approximately 2 instruction slots used
+#endif
+
+const BYTE g_vs20_flipyvs[] =
+{
+ 0, 2, 254, 255, 254, 255,
+ 36, 0, 67, 84, 65, 66,
+ 28, 0, 0, 0, 87, 0,
+ 0, 0, 0, 2, 254, 255,
+ 1, 0, 0, 0, 28, 0,
+ 0, 0, 0, 1, 0, 0,
+ 80, 0, 0, 0, 48, 0,
+ 0, 0, 2, 0, 0, 0,
+ 1, 0, 0, 0, 64, 0,
+ 0, 0, 0, 0, 0, 0,
+ 104, 97, 108, 102, 80, 105,
+ 120, 101, 108, 83, 105, 122,
+ 101, 0, 171, 171, 1, 0,
+ 3, 0, 1, 0, 4, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 118, 115, 95, 50,
+ 95, 48, 0, 77, 105, 99,
+ 114, 111, 115, 111, 102, 116,
+ 32, 40, 82, 41, 32, 72,
+ 76, 83, 76, 32, 83, 104,
+ 97, 100, 101, 114, 32, 67,
+ 111, 109, 112, 105, 108, 101,
+ 114, 32, 54, 46, 51, 46,
+ 57, 54, 48, 48, 46, 49,
+ 54, 51, 56, 52, 0, 171,
+ 171, 171, 81, 0, 0, 5,
+ 1, 0, 15, 160, 0, 0,
+ 0, 63, 0, 0, 128, 63,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 31, 0, 0, 2,
+ 0, 0, 0, 128, 0, 0,
+ 15, 144, 2, 0, 0, 3,
+ 0, 0, 15, 192, 0, 0,
+ 228, 144, 0, 0, 228, 160,
+ 4, 0, 0, 4, 0, 0,
+ 15, 224, 0, 0, 228, 144,
+ 1, 0, 80, 160, 1, 0,
+ 160, 160, 255, 255, 0, 0
+};
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceps.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceps.h
new file mode 100755
index 000000000..bdd25ac13
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceps.h
@@ -0,0 +1,94 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+//
+// Parameters:
+//
+// float4 add;
+// float4 mult;
+// sampler2D tex;
+//
+//
+// Registers:
+//
+// Name Reg Size
+// ------------ ----- ----
+// mult c0 1
+// add c1 1
+// tex s0 1
+//
+
+ ps_2_0
+ dcl t0.xy
+ dcl_2d s0
+ texld r0, t0, s0
+ mov r1.xw, c0
+ mad r0.x, r0.x, r1.x, c1.x
+ mad r0.y, r0.w, r1.w, c1.w
+ mov r1.xyz, r0.x
+ mov r1.w, r0.y
+ mov oC0, r1
+
+// approximately 7 instruction slots used (1 texture, 6 arithmetic)
+#endif
+
+const BYTE g_ps20_luminanceps[] =
+{
+ 0, 2, 255, 255, 254, 255,
+ 50, 0, 67, 84, 65, 66,
+ 28, 0, 0, 0, 143, 0,
+ 0, 0, 0, 2, 255, 255,
+ 3, 0, 0, 0, 28, 0,
+ 0, 0, 0, 1, 0, 0,
+ 136, 0, 0, 0, 88, 0,
+ 0, 0, 2, 0, 1, 0,
+ 1, 0, 0, 0, 92, 0,
+ 0, 0, 0, 0, 0, 0,
+ 108, 0, 0, 0, 2, 0,
+ 0, 0, 1, 0, 0, 0,
+ 92, 0, 0, 0, 0, 0,
+ 0, 0, 113, 0, 0, 0,
+ 3, 0, 0, 0, 1, 0,
+ 0, 0, 120, 0, 0, 0,
+ 0, 0, 0, 0, 97, 100,
+ 100, 0, 1, 0, 3, 0,
+ 1, 0, 4, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 109, 117, 108, 116, 0, 116,
+ 101, 120, 0, 171, 171, 171,
+ 4, 0, 12, 0, 1, 0,
+ 1, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 112, 115,
+ 95, 50, 95, 48, 0, 77,
+ 105, 99, 114, 111, 115, 111,
+ 102, 116, 32, 40, 82, 41,
+ 32, 72, 76, 83, 76, 32,
+ 83, 104, 97, 100, 101, 114,
+ 32, 67, 111, 109, 112, 105,
+ 108, 101, 114, 32, 54, 46,
+ 51, 46, 57, 54, 48, 48,
+ 46, 49, 54, 51, 56, 52,
+ 0, 171, 171, 171, 31, 0,
+ 0, 2, 0, 0, 0, 128,
+ 0, 0, 3, 176, 31, 0,
+ 0, 2, 0, 0, 0, 144,
+ 0, 8, 15, 160, 66, 0,
+ 0, 3, 0, 0, 15, 128,
+ 0, 0, 228, 176, 0, 8,
+ 228, 160, 1, 0, 0, 2,
+ 1, 0, 9, 128, 0, 0,
+ 228, 160, 4, 0, 0, 4,
+ 0, 0, 1, 128, 0, 0,
+ 0, 128, 1, 0, 0, 128,
+ 1, 0, 0, 160, 4, 0,
+ 0, 4, 0, 0, 2, 128,
+ 0, 0, 255, 128, 1, 0,
+ 255, 128, 1, 0, 255, 160,
+ 1, 0, 0, 2, 1, 0,
+ 7, 128, 0, 0, 0, 128,
+ 1, 0, 0, 2, 1, 0,
+ 8, 128, 0, 0, 85, 128,
+ 1, 0, 0, 2, 0, 8,
+ 15, 128, 1, 0, 228, 128,
+ 255, 255, 0, 0
+};
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/passthroughps.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/passthroughps.h
new file mode 100755
index 000000000..337af92ec
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/passthroughps.h
@@ -0,0 +1,61 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+//
+// Parameters:
+//
+// sampler2D tex;
+//
+//
+// Registers:
+//
+// Name Reg Size
+// ------------ ----- ----
+// tex s0 1
+//
+
+ ps_2_0
+ dcl t0.xy
+ dcl_2d s0
+ texld r0, t0, s0
+ mov oC0, r0
+
+// approximately 2 instruction slots used (1 texture, 1 arithmetic)
+#endif
+
+const BYTE g_ps20_passthroughps[] =
+{
+ 0, 2, 255, 255, 254, 255,
+ 33, 0, 67, 84, 65, 66,
+ 28, 0, 0, 0, 75, 0,
+ 0, 0, 0, 2, 255, 255,
+ 1, 0, 0, 0, 28, 0,
+ 0, 0, 0, 1, 0, 0,
+ 68, 0, 0, 0, 48, 0,
+ 0, 0, 3, 0, 0, 0,
+ 1, 0, 0, 0, 52, 0,
+ 0, 0, 0, 0, 0, 0,
+ 116, 101, 120, 0, 4, 0,
+ 12, 0, 1, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 112, 115, 95, 50,
+ 95, 48, 0, 77, 105, 99,
+ 114, 111, 115, 111, 102, 116,
+ 32, 40, 82, 41, 32, 72,
+ 76, 83, 76, 32, 83, 104,
+ 97, 100, 101, 114, 32, 67,
+ 111, 109, 112, 105, 108, 101,
+ 114, 32, 54, 46, 51, 46,
+ 57, 54, 48, 48, 46, 49,
+ 54, 51, 56, 52, 0, 171,
+ 171, 171, 31, 0, 0, 2,
+ 0, 0, 0, 128, 0, 0,
+ 3, 176, 31, 0, 0, 2,
+ 0, 0, 0, 144, 0, 8,
+ 15, 160, 66, 0, 0, 3,
+ 0, 0, 15, 128, 0, 0,
+ 228, 176, 0, 8, 228, 160,
+ 1, 0, 0, 2, 0, 8,
+ 15, 128, 0, 0, 228, 128,
+ 255, 255, 0, 0
+};
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/standardvs.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/standardvs.h
new file mode 100755
index 000000000..a83050d8c
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/standardvs.h
@@ -0,0 +1,66 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+//
+// Parameters:
+//
+// float4 halfPixelSize;
+//
+//
+// Registers:
+//
+// Name Reg Size
+// ------------- ----- ----
+// halfPixelSize c0 1
+//
+
+ vs_2_0
+ def c1, 0.5, -0.5, 1, 0
+ dcl_position v0
+ add oPos, v0, c0
+ mad oT0, v0, c1.xyzz, c1.xxww
+
+// approximately 2 instruction slots used
+#endif
+
+const BYTE g_vs20_standardvs[] =
+{
+ 0, 2, 254, 255, 254, 255,
+ 36, 0, 67, 84, 65, 66,
+ 28, 0, 0, 0, 87, 0,
+ 0, 0, 0, 2, 254, 255,
+ 1, 0, 0, 0, 28, 0,
+ 0, 0, 0, 1, 0, 0,
+ 80, 0, 0, 0, 48, 0,
+ 0, 0, 2, 0, 0, 0,
+ 1, 0, 0, 0, 64, 0,
+ 0, 0, 0, 0, 0, 0,
+ 104, 97, 108, 102, 80, 105,
+ 120, 101, 108, 83, 105, 122,
+ 101, 0, 171, 171, 1, 0,
+ 3, 0, 1, 0, 4, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 118, 115, 95, 50,
+ 95, 48, 0, 77, 105, 99,
+ 114, 111, 115, 111, 102, 116,
+ 32, 40, 82, 41, 32, 72,
+ 76, 83, 76, 32, 83, 104,
+ 97, 100, 101, 114, 32, 67,
+ 111, 109, 112, 105, 108, 101,
+ 114, 32, 54, 46, 51, 46,
+ 57, 54, 48, 48, 46, 49,
+ 54, 51, 56, 52, 0, 171,
+ 171, 171, 81, 0, 0, 5,
+ 1, 0, 15, 160, 0, 0,
+ 0, 63, 0, 0, 0, 191,
+ 0, 0, 128, 63, 0, 0,
+ 0, 0, 31, 0, 0, 2,
+ 0, 0, 0, 128, 0, 0,
+ 15, 144, 2, 0, 0, 3,
+ 0, 0, 15, 192, 0, 0,
+ 228, 144, 0, 0, 228, 160,
+ 4, 0, 0, 4, 0, 0,
+ 15, 224, 0, 0, 228, 144,
+ 1, 0, 164, 160, 1, 0,
+ 240, 160, 255, 255, 0, 0
+};
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/generate_shaders.bat b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/generate_shaders.bat
new file mode 100755
index 000000000..19a99ba91
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/shaders/generate_shaders.bat
@@ -0,0 +1,63 @@
+@ECHO OFF
+REM
+REM Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+REM Use of this source code is governed by a BSD-style license that can be
+REM found in the LICENSE file.
+REM
+
+PATH %PATH%;%ProgramFiles(x86)%\Windows Kits\8.1\bin\x86;%DXSDK_DIR%\Utilities\bin\x86
+
+setlocal
+set errorCount=0
+set successCount=0
+set debug=0
+
+if "%1" == "debug" (
+ set debug=1
+)
+if "%1" == "release" (
+ set debug=0
+)
+
+:: | Input file | Entry point | Type | Output file | Debug |
+call:BuildShader Blit.vs standardvs vs_2_0 compiled\standardvs.h %debug%
+call:BuildShader Blit.vs flipyvs vs_2_0 compiled\flipyvs.h %debug%
+call:BuildShader Blit.ps passthroughps ps_2_0 compiled\passthroughps.h %debug%
+call:BuildShader Blit.ps luminanceps ps_2_0 compiled\luminanceps.h %debug%
+call:BuildShader Blit.ps componentmaskps ps_2_0 compiled\componentmaskps.h %debug%
+
+echo.
+
+if %successCount% GTR 0 (
+ echo %successCount% shaders compiled successfully.
+)
+if %errorCount% GTR 0 (
+ echo There were %errorCount% shader compilation errors.
+)
+
+endlocal
+exit /b
+
+:BuildShader
+set input=%~1
+set entry=%~2
+set type=%~3
+set output=%~4
+set debug=%~5
+
+if %debug% == 0 (
+ set "buildCMD=fxc /nologo /E %entry% /T %type% /Fh %output% %input%"
+) else (
+ set "buildCMD=fxc /nologo /Zi /Od /E %entry% /T %type% /Fh %output% %input%"
+)
+
+set error=0
+%buildCMD% || set error=1
+
+if %error% == 0 (
+ set /a successCount=%successCount%+1
+) else (
+ set /a errorCount=%errorCount%+1
+)
+
+exit /b
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h
new file mode 100755
index 000000000..aa05934bc
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h
@@ -0,0 +1,200 @@
+//
+// Copyright (c) 2002-2010 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.
+//
+
+// vertexconversion.h: A library of vertex conversion classes that can be used to build
+// the FormatConverter objects used by the buffer conversion system.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXCONVERSION_H_
+#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXCONVERSION_H_
+
+#include <limits>
+#include <cstdint>
+#include <cstddef>
+
+namespace rx
+{
+
+// Conversion types:
+// static const bool identity: true if this is an identity transform, false otherwise
+// static U convert(T): convert a single element from the input type to the output type
+// typedef ... OutputType: the type produced by this conversion
+
+template <class T>
+struct Identity
+{
+ static const bool identity = true;
+
+ typedef T OutputType;
+
+ static T convert(T x)
+ {
+ return x;
+ }
+};
+
+template <class FromT, class ToT>
+struct Cast
+{
+ static const bool identity = false;
+
+ typedef ToT OutputType;
+
+ static ToT convert(FromT x)
+ {
+ return static_cast<ToT>(x);
+ }
+};
+
+template <class T>
+struct Cast<T, T>
+{
+ static const bool identity = true;
+
+ typedef T OutputType;
+
+ static T convert(T x)
+ {
+ return static_cast<T>(x);
+ }
+};
+
+template <class T>
+struct Normalize
+{
+ static const bool identity = false;
+
+ typedef float OutputType;
+
+ static float convert(T x)
+ {
+ typedef std::numeric_limits<T> NL;
+ float f = static_cast<float>(x);
+
+ if (NL::is_signed)
+ {
+ // const float => VC2008 computes it at compile time
+ // static const float => VC2008 computes it the first time we get here, stores it to memory with static guard and all that.
+ const float divisor = 1.0f/(2*static_cast<float>(NL::max())+1);
+ return (2*f+1)*divisor;
+ }
+ else
+ {
+ return f/NL::max();
+ }
+ }
+};
+
+template <class FromType, std::size_t ScaleBits>
+struct FixedToFloat
+{
+ static const bool identity = false;
+
+ typedef float OutputType;
+
+ static float convert(FromType x)
+ {
+ const float divisor = 1.0f / static_cast<float>(static_cast<FromType>(1) << ScaleBits);
+ return static_cast<float>(x) * divisor;
+ }
+};
+
+// Widen types:
+// static const unsigned int initialWidth: number of components before conversion
+// static const unsigned int finalWidth: number of components after conversion
+
+// Float is supported at any size.
+template <std::size_t N>
+struct NoWiden
+{
+ static const std::size_t initialWidth = N;
+ static const std::size_t finalWidth = N;
+};
+
+// SHORT, norm-SHORT, norm-UNSIGNED_SHORT are supported but only with 2 or 4 components
+template <std::size_t N>
+struct WidenToEven
+{
+ static const std::size_t initialWidth = N;
+ static const std::size_t finalWidth = N+(N&1);
+};
+
+template <std::size_t N>
+struct WidenToFour
+{
+ static const std::size_t initialWidth = N;
+ static const std::size_t finalWidth = 4;
+};
+
+// Most types have 0 and 1 that are just that.
+template <class T>
+struct SimpleDefaultValues
+{
+ static T zero() { return static_cast<T>(0); }
+ static T one() { return static_cast<T>(1); }
+};
+
+// But normalised types only store [0,1] or [-1,1] so 1.0 is represented by the max value.
+template <class T>
+struct NormalizedDefaultValues
+{
+ static T zero() { return static_cast<T>(0); }
+ static T one() { return std::numeric_limits<T>::max(); }
+};
+
+// Converter:
+// static const bool identity: true if this is an identity transform (with no widening)
+// static const std::size_t finalSize: number of bytes per output vertex
+// static void convertArray(const void *in, std::size_t stride, std::size_t n, void *out): convert an array of vertices. Input may be strided, but output will be unstrided.
+
+template <class InT,
+ class WidenRule,
+ class Converter,
+ class DefaultValueRule = SimpleDefaultValues<InT>>
+struct VertexDataConverter
+{
+ typedef typename Converter::OutputType OutputType;
+ typedef InT InputType;
+
+ static const bool identity = (WidenRule::initialWidth == WidenRule::finalWidth) && Converter::identity;
+ static const std::size_t finalSize = WidenRule::finalWidth * sizeof(OutputType);
+
+ static void convertArray(const uint8_t *input, size_t stride, size_t n, uint8_t *output)
+ {
+ OutputType *out = reinterpret_cast<OutputType*>(output);
+
+ for (std::size_t i = 0; i < n; i++)
+ {
+ const InputType *ein = reinterpret_cast<const InputType*>(input + i * stride);
+
+ copyComponent(out, ein, 0, static_cast<OutputType>(DefaultValueRule::zero()));
+ copyComponent(out, ein, 1, static_cast<OutputType>(DefaultValueRule::zero()));
+ copyComponent(out, ein, 2, static_cast<OutputType>(DefaultValueRule::zero()));
+ copyComponent(out, ein, 3, static_cast<OutputType>(DefaultValueRule::one()));
+
+ out += WidenRule::finalWidth;
+ }
+ }
+
+ private:
+ static void copyComponent(OutputType *out, const InputType *in, std::size_t elementindex, OutputType defaultvalue)
+ {
+ if (WidenRule::finalWidth > elementindex)
+ {
+ if (WidenRule::initialWidth > elementindex)
+ {
+ out[elementindex] = Converter::convert(in[elementindex]);
+ }
+ else
+ {
+ out[elementindex] = defaultvalue;
+ }
+ }
+ }
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXCONVERSION_H_