diff options
Diffstat (limited to 'src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9')
34 files changed, 9182 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp new file mode 100644 index 0000000000..f486e5a4cc --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp @@ -0,0 +1,645 @@ +#include "precompiled.h" +// +// 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 "libGLESv2/renderer/d3d/d3d9/Blit9.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h" +#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" + +namespace +{ +#include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/standardvs.h" +#include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/flipyvs.h" +#include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/passthroughps.h" +#include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/luminanceps.h" +#include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h" + +const BYTE* const g_shaderCode[] = +{ + g_vs20_VS_standard, + g_vs20_VS_flipy, + g_ps20_PS_passthrough, + g_ps20_PS_luminance, + g_ps20_PS_componentmask +}; + +const size_t g_shaderSize[] = +{ + sizeof(g_vs20_VS_standard), + sizeof(g_vs20_VS_flipy), + sizeof(g_ps20_PS_passthrough), + sizeof(g_ps20_PS_luminance), + sizeof(g_ps20_PS_componentmask) +}; +} + +namespace rx +{ +Blit9::Blit9(rx::Renderer9 *renderer) + : mRenderer(renderer), mQuadVertexBuffer(NULL), mQuadVertexDeclaration(NULL), mSavedStateBlock(NULL), mSavedRenderTarget(NULL), mSavedDepthStencil(NULL) +{ + initGeometry(); + memset(mCompiledShaders, 0, sizeof(mCompiledShaders)); +} + +Blit9::~Blit9() +{ + SafeRelease(mSavedStateBlock); + SafeRelease(mQuadVertexBuffer); + SafeRelease(mQuadVertexDeclaration); + + for (int i = 0; i < SHADER_COUNT; i++) + { + SafeRelease(mCompiledShaders[i]); + } +} + +void Blit9::initGeometry() +{ + 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); + } + + void *lockPtr = NULL; + result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0); + + if (FAILED(result) || lockPtr == NULL) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::error(GL_OUT_OF_MEMORY); + } + + 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); + return gl::error(GL_OUT_OF_MEMORY); + } +} + +template <class D3DShaderType> +bool Blit9::setShader(ShaderId source, const char *profile, + D3DShaderType *(rx::Renderer9::*createShader)(const DWORD *, size_t length), + HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)) +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + D3DShaderType *shader; + + if (mCompiledShaders[source] != NULL) + { + shader = static_cast<D3DShaderType*>(mCompiledShaders[source]); + } + else + { + const BYTE* shaderCode = g_shaderCode[source]; + size_t shaderSize = g_shaderSize[source]; + + shader = (mRenderer->*createShader)(reinterpret_cast<const DWORD*>(shaderCode), shaderSize); + if (!shader) + { + ERR("Failed to create shader for blit operation"); + return false; + } + + mCompiledShaders[source] = shader; + } + + HRESULT hr = (device->*setShader)(shader); + + if (FAILED(hr)) + { + ERR("Failed to set shader for blit operation"); + return false; + } + + return true; +} + +bool Blit9::setVertexShader(ShaderId shader) +{ + return setShader<IDirect3DVertexShader9>(shader, "vs_2_0", &rx::Renderer9::createVertexShader, &IDirect3DDevice9::SetVertexShader); +} + +bool Blit9::setPixelShader(ShaderId shader) +{ + return setShader<IDirect3DPixelShader9>(shader, "ps_2_0", &rx::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; +} + +bool Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) +{ + IDirect3DTexture9 *texture = copySurfaceToTexture(source, getSurfaceRect(source)); + if (!texture) + { + return false; + } + + 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), 0, 0); + + render(); + + SafeRelease(texture); + + restoreState(); + + return true; +} + +bool Blit9::copy(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level) +{ + RenderTarget9 *renderTarget = NULL; + IDirect3DSurface9 *source = NULL; + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); + + if (colorbuffer) + { + renderTarget = RenderTarget9::makeRenderTarget9(colorbuffer->getRenderTarget()); + } + + if (renderTarget) + { + source = renderTarget->getSurface(); + } + + if (!source) + { + ERR("Failed to retrieve the render target."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage->getStorageInstance()); + IDirect3DSurface9 *destSurface = storage9->getSurfaceLevel(level, true); + bool result = false; + + if (destSurface) + { + result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface); + SafeRelease(destSurface); + } + + SafeRelease(source); + return result; +} + +bool Blit9::copy(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level) +{ + RenderTarget9 *renderTarget = NULL; + IDirect3DSurface9 *source = NULL; + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); + + if (colorbuffer) + { + renderTarget = RenderTarget9::makeRenderTarget9(colorbuffer->getRenderTarget()); + } + + if (renderTarget) + { + source = renderTarget->getSurface(); + } + + if (!source) + { + ERR("Failed to retrieve the render target."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage->getStorageInstance()); + IDirect3DSurface9 *destSurface = storage9->getCubeMapSurface(target, level, true); + bool result = false; + + if (destSurface) + { + result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface); + SafeRelease(destSurface); + } + + SafeRelease(source); + return result; +} + +bool Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) +{ + if (!dest) + { + return false; + } + + 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 = {xoffset, yoffset, xoffset + (sourceRect.right - sourceRect.left), yoffset + (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, false); + } + } + else + { + return formatConvert(source, sourceRect, destFormat, xoffset, yoffset, dest); + } + return true; +} + +bool Blit9::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) +{ + IDirect3DTexture9 *texture = copySurfaceToTexture(source, sourceRect); + if (!texture) + { + return false; + } + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + saveState(); + + device->SetTexture(0, texture); + device->SetRenderTarget(0, dest); + + setViewport(sourceRect, xoffset, yoffset); + + setCommonBlitState(); + if (setFormatConvertShaders(destFormat)) + { + render(); + } + + SafeRelease(texture); + + restoreState(); + + return true; +} + +bool Blit9::setFormatConvertShaders(GLenum destFormat) +{ + bool okay = setVertexShader(SHADER_VS_STANDARD); + + 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: + okay = okay && setPixelShader(SHADER_PS_COMPONENTMASK); + break; + + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + okay = okay && setPixelShader(SHADER_PS_LUMINANCE); + break; + } + + if (!okay) + { + return false; + } + + 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 true; +} + +IDirect3DTexture9 *Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect) +{ + if (!surface) + { + return NULL; + } + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + D3DSURFACE_DESC sourceDesc; + surface->GetDesc(&sourceDesc); + + // Copy the render target into a texture + IDirect3DTexture9 *texture; + HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 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, (IDirect3DTexture9*)NULL); + } + + 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, (IDirect3DTexture9*)NULL); + } + + mRenderer->endScene(); + result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE); + + SafeRelease(textureSurface); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + SafeRelease(texture); + return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL); + } + + return texture; +} + +void Blit9::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset) +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + D3DVIEWPORT9 vp; + vp.X = xoffset; + vp.Y = yoffset; + 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/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h new file mode 100644 index 0000000000..3635bca932 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h @@ -0,0 +1,94 @@ +// +// 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 LIBGLESV2_BLIT9_H_ +#define LIBGLESV2_BLIT9_H_ + +#include "common/angleutils.h" + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ +class Renderer9; +class TextureStorageInterface2D; +class TextureStorageInterfaceCube; + +class Blit9 +{ + public: + explicit Blit9(Renderer9 *renderer); + ~Blit9(); + + // Copy from source surface to dest surface. + // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) + bool copy(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level); + bool copy(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *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. + bool formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest); + + // 2x2 box filter sample from source to dest. + // Requires that source is RGB(A) and dest has the same format as source. + bool boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); + + private: + rx::Renderer9 *mRenderer; + + IDirect3DVertexBuffer9 *mQuadVertexBuffer; + IDirect3DVertexDeclaration9 *mQuadVertexDeclaration; + + void initGeometry(); + + bool setFormatConvertShaders(GLenum destFormat); + + bool copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest); + IDirect3DTexture9 *copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect); + void setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset); + 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> + bool setShader(ShaderId source, const char *profile, + D3DShaderType *(Renderer9::*createShader)(const DWORD *, size_t length), + HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)); + + bool setVertexShader(ShaderId shader); + bool setPixelShader(ShaderId shader); + void render(); + + void saveState(); + void restoreState(); + IDirect3DStateBlock9 *mSavedStateBlock; + IDirect3DSurface9 *mSavedRenderTarget; + IDirect3DSurface9 *mSavedDepthStencil; + + DISALLOW_COPY_AND_ASSIGN(Blit9); +}; +} + +#endif // LIBGLESV2_BLIT9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp new file mode 100644 index 0000000000..347bde0c65 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp @@ -0,0 +1,126 @@ +#include "precompiled.h" +// +// 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 "libGLESv2/renderer/d3d/d3d9/Buffer9.h" +#include "libGLESv2/main.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ + +Buffer9::Buffer9(rx::Renderer9 *renderer) + : BufferD3D(), + mRenderer(renderer), + mSize(0) +{ + +} + +Buffer9::~Buffer9() +{ + +} + +Buffer9 *Buffer9::makeBuffer9(BufferImpl *buffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(Buffer9*, buffer)); + return static_cast<Buffer9*>(buffer); +} + +void Buffer9::clear() +{ + mSize = 0; +} + +void Buffer9::setData(const void* data, size_t size, GLenum usage) +{ + if (size > mMemory.size()) + { + if (!mMemory.resize(size)) + { + return gl::error(GL_OUT_OF_MEMORY); + } + } + + mSize = size; + if (data) + { + memcpy(mMemory.data(), data, size); + } + + mIndexRangeCache.clear(); + + invalidateStaticData(); + + if (usage == GL_STATIC_DRAW) + { + initializeStaticData(); + } +} + +void *Buffer9::getData() +{ + return mMemory.data(); +} + +void Buffer9::setSubData(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); + } + } + + mSize = std::max(mSize, offset + size); + if (data) + { + memcpy(mMemory.data() + offset, data, size); + } + + mIndexRangeCache.invalidateRange(offset, size); + + invalidateStaticData(); +} + +void Buffer9::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) +{ + Buffer9* sourceBuffer = makeBuffer9(source); + if (sourceBuffer) + { + memcpy(mMemory.data() + destOffset, sourceBuffer->mMemory.data() + sourceOffset, size); + } + + invalidateStaticData(); +} + +// We do not suppot buffer mapping in D3D9 +GLvoid* Buffer9::map(size_t offset, size_t length, GLbitfield access) +{ + UNREACHABLE(); + return NULL; +} + +void Buffer9::unmap() +{ + UNREACHABLE(); +} + +void Buffer9::markTransformFeedbackUsage() +{ + UNREACHABLE(); +} + +Renderer* Buffer9::getRenderer() +{ + return mRenderer; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.h new file mode 100644 index 0000000000..ec25ec30c9 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.h @@ -0,0 +1,53 @@ +// +// 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 LIBGLESV2_RENDERER_BUFFER9_H_ +#define LIBGLESV2_RENDERER_BUFFER9_H_ + +#include "libGLESv2/renderer/d3d/BufferD3D.h" +#include "libGLESv2/renderer/d3d/MemoryBuffer.h" +#include "libGLESv2/angletypes.h" + +namespace rx +{ +class Renderer9; + +class Buffer9 : public BufferD3D +{ + public: + Buffer9(rx::Renderer9 *renderer); + virtual ~Buffer9(); + + static Buffer9 *makeBuffer9(BufferImpl *buffer); + + // BufferD3D implementation + virtual size_t getSize() const { return mSize; } + virtual void clear(); + virtual bool supportsDirectBinding() const { return false; } + virtual Renderer* getRenderer(); + + // BufferImpl implementation + virtual void setData(const void* data, size_t size, GLenum usage); + virtual void *getData(); + virtual void setSubData(const void* data, size_t size, size_t offset); + virtual void copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); + virtual GLvoid* map(size_t offset, size_t length, GLbitfield access); + virtual void unmap(); + virtual void markTransformFeedbackUsage(); + + private: + DISALLOW_COPY_AND_ASSIGN(Buffer9); + + rx::Renderer9 *mRenderer; + MemoryBuffer mMemory; + size_t mSize; +}; + +} + +#endif // LIBGLESV2_RENDERER_BUFFER9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp new file mode 100644 index 0000000000..d2437cadf3 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp @@ -0,0 +1,73 @@ +#include "precompiled.h" +// +// 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::Fence9 class. + +#include "libGLESv2/renderer/d3d/d3d9/Fence9.h" +#include "libGLESv2/main.h" +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ + +Fence9::Fence9(rx::Renderer9 *renderer) +{ + mRenderer = renderer; + mQuery = NULL; +} + +Fence9::~Fence9() +{ + SafeRelease(mQuery); +} + +bool Fence9::isSet() const +{ + return mQuery != NULL; +} + +void Fence9::set() +{ + if (!mQuery) + { + mQuery = mRenderer->allocateEventQuery(); + if (!mQuery) + { + return gl::error(GL_OUT_OF_MEMORY); + } + } + + HRESULT result = mQuery->Issue(D3DISSUE_END); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); +} + +bool Fence9::test(bool flushCommandBuffer) +{ + 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, true); + } + + ASSERT(result == S_OK || result == S_FALSE); + + return (result == S_OK); +} + +bool Fence9::hasError() const +{ + return mRenderer->isDeviceLost(); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.h new file mode 100644 index 0000000000..e923a2178c --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/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::Fence9 class which implements rx::FenceImpl. + +#ifndef LIBGLESV2_RENDERER_FENCE9_H_ +#define LIBGLESV2_RENDERER_FENCE9_H_ + +#include "libGLESv2/renderer/FenceImpl.h" + +namespace rx +{ +class Renderer9; + +class Fence9 : public FenceImpl +{ + public: + explicit Fence9(rx::Renderer9 *renderer); + virtual ~Fence9(); + + bool isSet() const; + void set(); + bool test(bool flushCommandBuffer); + bool hasError() const; + + private: + DISALLOW_COPY_AND_ASSIGN(Fence9); + + rx::Renderer9 *mRenderer; + IDirect3DQuery9 *mQuery; +}; + +} + +#endif // LIBGLESV2_RENDERER_FENCE9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp new file mode 100644 index 0000000000..e237c3b6e1 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp @@ -0,0 +1,703 @@ + +#include "precompiled.h" +// +// 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 "libGLESv2/renderer/d3d/d3d9/Image9.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" +#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" +#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" +#include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h" + +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" + +namespace rx +{ + +Image9::Image9() +{ + mSurface = NULL; + mRenderer = NULL; + + mD3DPool = D3DPOOL_SYSTEMMEM; + mD3DFormat = D3DFMT_UNKNOWN; +} + +Image9::~Image9() +{ + SafeRelease(mSurface); +} + +void Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface) +{ + D3DSURFACE_DESC destDesc; + HRESULT result = destSurface->GetDesc(&destDesc); + ASSERT(SUCCEEDED(result)); + + D3DSURFACE_DESC sourceDesc; + result = sourceSurface->GetDesc(&sourceDesc); + ASSERT(SUCCEEDED(result)); + + ASSERT(sourceDesc.Format == destDesc.Format); + ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width); + ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height); + + MipGenerationFunction mipFunction = d3d9::GetMipGenerationFunction(sourceDesc.Format); + ASSERT(mipFunction != NULL); + + D3DLOCKED_RECT sourceLocked = {0}; + result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY); + ASSERT(SUCCEEDED(result)); + + D3DLOCKED_RECT destLocked = {0}; + result = destSurface->LockRect(&destLocked, NULL, 0); + ASSERT(SUCCEEDED(result)); + + const uint8_t *sourceData = reinterpret_cast<const uint8_t*>(sourceLocked.pBits); + uint8_t *destData = reinterpret_cast<uint8_t*>(destLocked.pBits); + + if (sourceData && destData) + { + mipFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData, sourceLocked.Pitch, 0, + destData, destLocked.Pitch, 0); + } + + destSurface->UnlockRect(); + sourceSurface->UnlockRect(); +} + +Image9 *Image9::makeImage9(Image *img) +{ + ASSERT(HAS_DYNAMIC_TYPE(rx::Image9*, img)); + return static_cast<rx::Image9*>(img); +} + +void Image9::generateMipmap(Image9 *dest, Image9 *source) +{ + IDirect3DSurface9 *sourceSurface = source->getSurface(); + if (sourceSurface == NULL) + return gl::error(GL_OUT_OF_MEMORY); + + IDirect3DSurface9 *destSurface = dest->getSurface(); + generateMip(destSurface, sourceSurface); + + dest->markDirty(); +} + +void Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source) +{ + D3DLOCKED_RECT sourceLock = {0}; + D3DLOCKED_RECT destLock = {0}; + + source->LockRect(&sourceLock, NULL, 0); + dest->LockRect(&destLock, NULL, 0); + + if (sourceLock.pBits && destLock.pBits) + { + D3DSURFACE_DESC desc; + source->GetDesc(&desc); + + int blockHeight = d3d9::GetBlockHeight(desc.Format); + int rows = desc.Height / blockHeight; + + int bytes = d3d9::GetBlockSize(desc.Format, desc.Width, blockHeight); + ASSERT(bytes <= sourceLock.Pitch && bytes <= destLock.Pitch); + + for(int i = 0; i < rows; i++) + { + memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes); + } + + source->UnlockRect(); + dest->UnlockRect(); + } + else UNREACHABLE(); +} + +bool Image9::redefine(rx::Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) +{ + // 3D textures are not supported by the D3D9 backend. + ASSERT(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 != width || + mHeight != height || + mDepth != depth || + mInternalFormat != internalformat || + forceRelease) + { + mRenderer = Renderer9::makeRenderer9(renderer); + + mWidth = width; + mHeight = height; + mDepth = depth; + mInternalFormat = internalformat; + + // compute the d3d format that will be used + mD3DFormat = gl_d3d9::GetTextureFormat(internalformat); + mActualFormat = d3d9_gl::GetInternalFormat(mD3DFormat); + mRenderable = gl_d3d9::GetRenderFormat(internalformat) != D3DFMT_UNKNOWN; + + SafeRelease(mSurface); + mDirty = gl_d3d9::RequiresTextureDataInitialization(mInternalFormat); + + return true; + } + + return false; +} + +void Image9::createSurface() +{ + if(mSurface) + { + return; + } + + 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); + ERR("Creating image surface failed."); + return gl::error(GL_OUT_OF_MEMORY); + } + + newTexture->GetSurfaceLevel(levelToFetch, &newSurface); + SafeRelease(newTexture); + + if (gl_d3d9::RequiresTextureDataInitialization(mInternalFormat)) + { + InitializeTextureDataFunction initializeFunc = gl_d3d9::GetTextureDataInitializationFunction(mInternalFormat); + + 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)); + + initializeFunc(mWidth, mHeight, 1, reinterpret_cast<uint8_t*>(lockedRect.pBits), lockedRect.Pitch, 0); + + result = newSurface->UnlockRect(); + ASSERT(SUCCEEDED(result)); + } + } + + mSurface = newSurface; + mDirty = false; + mD3DPool = poolToUse; +} + +HRESULT Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect) +{ + createSurface(); + + HRESULT result = D3DERR_INVALIDCALL; + + if (mSurface) + { + result = mSurface->LockRect(lockedRect, rect, 0); + ASSERT(SUCCEEDED(result)); + + mDirty = true; + } + + return result; +} + +void Image9::unlock() +{ + if (mSurface) + { + HRESULT result = mSurface->UnlockRect(); + UNUSED_ASSERTION_VARIABLE(result); + 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 || gl_d3d9::RequiresTextureDataInitialization(mInternalFormat)) && mDirty; +} + +IDirect3DSurface9 *Image9::getSurface() +{ + createSurface(); + + return mSurface; +} + +void Image9::setManagedSurface(TextureStorageInterface2D *storage, int level) +{ + TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage->getStorageInstance()); + setManagedSurface(storage9->getSurfaceLevel(level, false)); +} + +void Image9::setManagedSurface(TextureStorageInterfaceCube *storage, int face, int level) +{ + TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage->getStorageInstance()); + setManagedSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false)); +} + +void 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) + { + copyLockableSurfaces(surface, mSurface); + SafeRelease(mSurface); + } + + mSurface = surface; + mD3DPool = desc.Pool; + } +} + +bool Image9::copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + ASSERT(getSurface() != NULL); + TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage->getStorageInstance()); + return copyToSurface(storage9->getSurfaceLevel(level, true), xoffset, yoffset, width, height); +} + +bool Image9::copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + ASSERT(getSurface() != NULL); + TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage->getStorageInstance()); + return copyToSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true), xoffset, yoffset, width, height); +} + +bool Image9::copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) +{ + // 3D textures are not supported by the D3D9 backend. + UNREACHABLE(); + return false; +} + +bool Image9::copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height) +{ + // 2D array textures are not supported by the D3D9 backend. + UNREACHABLE(); + return false; +} + +bool Image9::copyToSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + ASSERT(width > 0 && height > 0); + + if (!destSurface) + return false; + + IDirect3DSurface9 *sourceSurface = getSurface(); + + if (sourceSurface && sourceSurface != destSurface) + { + RECT rect; + rect.left = xoffset; + rect.top = yoffset; + rect.right = xoffset + width; + rect.bottom = yoffset + 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 (SUCCEEDED(result)) + { + copyLockableSurfaces(surf, sourceSurface); + result = device->UpdateSurface(surf, &rect, destSurface, &point); + ASSERT(SUCCEEDED(result)); + SafeRelease(surf); + } + } + else + { + // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools + HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + } + } + + SafeRelease(destSurface); + return true; +} + +// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input +// into the target pixel rectangle. +void Image9::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint unpackAlignment, GLenum type, const void *input) +{ + // 3D textures are not supported by the D3D9 backend. + ASSERT(zoffset == 0 && depth == 1); + + GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, type, width, unpackAlignment); + + LoadImageFunction loadFunction = d3d9::GetImageLoadFunction(mInternalFormat); + ASSERT(loadFunction != NULL); + + RECT lockRect = + { + xoffset, yoffset, + xoffset + width, yoffset + height + }; + + D3DLOCKED_RECT locked; + HRESULT result = lock(&locked, &lockRect); + if (FAILED(result)) + { + return; + } + + loadFunction(width, height, depth, + reinterpret_cast<const uint8_t*>(input), inputRowPitch, 0, + reinterpret_cast<uint8_t*>(locked.pBits), locked.Pitch, 0); + + unlock(); +} + +void Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + const void *input) +{ + // 3D textures are not supported by the D3D9 backend. + ASSERT(zoffset == 0 && depth == 1); + + GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, GL_UNSIGNED_BYTE, width, 1); + GLsizei inputDepthPitch = gl::GetDepthPitch(mInternalFormat, GL_UNSIGNED_BYTE, width, height, 1); + + ASSERT(xoffset % d3d9::GetBlockWidth(mD3DFormat) == 0); + ASSERT(yoffset % d3d9::GetBlockHeight(mD3DFormat) == 0); + + LoadImageFunction loadFunction = d3d9::GetImageLoadFunction(mInternalFormat); + ASSERT(loadFunction != NULL); + + RECT lockRect = + { + xoffset, yoffset, + xoffset + width, yoffset + height + }; + + D3DLOCKED_RECT locked; + HRESULT result = lock(&locked, &lockRect); + if (FAILED(result)) + { + return; + } + + loadFunction(width, height, depth, + reinterpret_cast<const uint8_t*>(input), inputRowPitch, inputDepthPitch, + reinterpret_cast<uint8_t*>(locked.pBits), locked.Pitch, 0); + + unlock(); +} + +// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures +void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +{ + // ES3.0 only behaviour to copy into a 3d texture + ASSERT(zoffset == 0); + + RenderTarget9 *renderTarget = NULL; + IDirect3DSurface9 *surface = NULL; + gl::FramebufferAttachment *colorbuffer = source->getColorbuffer(0); + + if (colorbuffer) + { + renderTarget = RenderTarget9::makeRenderTarget9(colorbuffer->getRenderTarget()); + } + + if (renderTarget) + { + surface = renderTarget->getSurface(); + } + + if (!surface) + { + ERR("Failed to retrieve the render target."); + return gl::error(GL_OUT_OF_MEMORY); + } + + 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)) + { + ERR("Could not create matching destination surface."); + SafeRelease(surface); + return gl::error(GL_OUT_OF_MEMORY); + } + + result = device->GetRenderTargetData(surface, renderTargetData); + + if (FAILED(result)) + { + ERR("GetRenderTargetData unexpectedly failed."); + SafeRelease(renderTargetData); + SafeRelease(surface); + return gl::error(GL_OUT_OF_MEMORY); + } + + RECT sourceRect = {x, y, x + width, y + height}; + RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height}; + + D3DLOCKED_RECT sourceLock = {0}; + result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0); + + if (FAILED(result)) + { + ERR("Failed to lock the source surface (rectangle might be invalid)."); + SafeRelease(renderTargetData); + SafeRelease(surface); + return gl::error(GL_OUT_OF_MEMORY); + } + + D3DLOCKED_RECT destLock = {0}; + result = lock(&destLock, &destRect); + + if (FAILED(result)) + { + ERR("Failed to lock the destination surface (rectangle might be invalid)."); + renderTargetData->UnlockRect(); + SafeRelease(renderTargetData); + SafeRelease(surface); + return gl::error(GL_OUT_OF_MEMORY); + } + + if (destLock.pBits && sourceLock.pBits) + { + unsigned char *source = (unsigned char*)sourceLock.pBits; + unsigned char *dest = (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(dest, source, 4 * width); + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + case D3DFMT_L8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + dest[x] = source[x * 4 + 2]; + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + case D3DFMT_A8L8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + dest[x * 2 + 0] = source[x * 4 + 2]; + dest[x * 2 + 1] = source[x * 4 + 3]; + } + + source += sourceLock.Pitch; + dest += 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*)source)[x]; + unsigned char red = (rgb & 0xF800) >> 8; + unsigned char green = (rgb & 0x07E0) >> 3; + unsigned char blue = (rgb & 0x001F) << 3; + dest[x + 0] = blue | (blue >> 5); + dest[x + 1] = green | (green >> 6); + dest[x + 2] = red | (red >> 5); + dest[x + 3] = 0xFF; + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + case D3DFMT_L8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + unsigned char red = source[x * 2 + 1] & 0xF8; + dest[x] = red | (red >> 5); + } + + source += sourceLock.Pitch; + dest += 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*)source)[x]; + unsigned char red = (argb & 0x7C00) >> 7; + unsigned char green = (argb & 0x03E0) >> 2; + unsigned char blue = (argb & 0x001F) << 3; + dest[x + 0] = blue | (blue >> 5); + dest[x + 1] = green | (green >> 5); + dest[x + 2] = red | (red >> 5); + dest[x + 3] = 0xFF; + } + + source += sourceLock.Pitch; + dest += 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*)source)[x]; + unsigned char red = (argb & 0x7C00) >> 7; + unsigned char green = (argb & 0x03E0) >> 2; + unsigned char blue = (argb & 0x001F) << 3; + unsigned char alpha = (signed short)argb >> 15; + dest[x + 0] = blue | (blue >> 5); + dest[x + 1] = green | (green >> 5); + dest[x + 2] = red | (red >> 5); + dest[x + 3] = alpha; + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + case D3DFMT_L8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + unsigned char red = source[x * 2 + 1] & 0x7C; + dest[x] = (red << 1) | (red >> 4); + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + case D3DFMT_A8L8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + unsigned char red = source[x * 2 + 1] & 0x7C; + dest[x * 2 + 0] = (red << 1) | (red >> 4); + dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7; + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + default: + UNREACHABLE(); + } + break; + default: + UNREACHABLE(); + } + } + + unlock(); + renderTargetData->UnlockRect(); + + SafeRelease(renderTargetData); + SafeRelease(surface); + + mDirty = true; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h new file mode 100644 index 0000000000..2d1536f24b --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/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 LIBGLESV2_RENDERER_IMAGE9_H_ +#define LIBGLESV2_RENDERER_IMAGE9_H_ + +#include "libGLESv2/renderer/d3d/ImageD3D.h" +#include "common/debug.h" + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ +class Renderer; +class Renderer9; +class TextureStorageInterface2D; +class TextureStorageInterfaceCube; + +class Image9 : public ImageD3D +{ + public: + Image9(); + ~Image9(); + + static Image9 *makeImage9(Image *img); + + static void generateMipmap(Image9 *dest, Image9 *source); + static void generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface); + static void copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source); + + virtual bool redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease); + + D3DFORMAT getD3DFormat() const; + + virtual bool isDirty() const; + IDirect3DSurface9 *getSurface(); + + virtual void setManagedSurface(TextureStorageInterface2D *storage, int level); + virtual void setManagedSurface(TextureStorageInterfaceCube *storage, int face, int level); + virtual bool copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + virtual bool copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + virtual bool copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); + virtual bool copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height); + + virtual void loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint unpackAlignment, GLenum type, const void *input); + virtual void loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + const void *input); + + virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset,GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + + private: + DISALLOW_COPY_AND_ASSIGN(Image9); + + void createSurface(); + void setManagedSurface(IDirect3DSurface9 *surface); + bool copyToSurface(IDirect3DSurface9 *dest, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + + HRESULT lock(D3DLOCKED_RECT *lockedRect, const RECT *rect); + void unlock(); + + Renderer9 *mRenderer; + + D3DPOOL mD3DPool; // can only be D3DPOOL_SYSTEMMEM or D3DPOOL_MANAGED since it needs to be lockable. + D3DFORMAT mD3DFormat; + + IDirect3DSurface9 *mSurface; +}; +} + +#endif // LIBGLESV2_RENDERER_IMAGE9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.cpp new file mode 100644 index 0000000000..472e6981a8 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.cpp @@ -0,0 +1,199 @@ +#include "precompiled.h" +// +// 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 "libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h" +#include "libGLESv2/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); +} + +bool IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) +{ + SafeRelease(mIndexBuffer); + + updateSerial(); + + if (bufferSize > 0) + { + D3DFORMAT format; + if (indexType == GL_UNSIGNED_SHORT || indexType == GL_UNSIGNED_BYTE) + { + format = D3DFMT_INDEX16; + } + else if (indexType == GL_UNSIGNED_INT) + { + if (mRenderer->getRendererExtensions().elementIndexUint) + { + format = D3DFMT_INDEX32; + } + else + { + ERR("Attempted to create a 32-bit index buffer but renderer does not support 32-bit indices."); + return false; + } + } + else + { + ERR("Invalid index type %u.", indexType); + return false; + } + + DWORD usageFlags = D3DUSAGE_WRITEONLY; + if (dynamic) + { + usageFlags |= D3DUSAGE_DYNAMIC; + } + + HRESULT result = mRenderer->createIndexBuffer(bufferSize, usageFlags, format, &mIndexBuffer); + if (FAILED(result)) + { + ERR("Failed to create an index buffer of size %u, result: 0x%08x.", mBufferSize, result); + return false; + } + } + + mBufferSize = bufferSize; + mIndexType = indexType; + mDynamic = dynamic; + + return true; +} + +IndexBuffer9 *IndexBuffer9::makeIndexBuffer9(IndexBuffer *indexBuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(IndexBuffer9*, indexBuffer)); + return static_cast<IndexBuffer9*>(indexBuffer); +} + +bool IndexBuffer9::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory) +{ + if (mIndexBuffer) + { + DWORD lockFlags = mDynamic ? D3DLOCK_NOOVERWRITE : 0; + + void *mapPtr = NULL; + HRESULT result = mIndexBuffer->Lock(offset, size, &mapPtr, lockFlags); + if (FAILED(result)) + { + ERR("Index buffer lock failed with error 0x%08x", result); + return false; + } + + *outMappedMemory = mapPtr; + return true; + } + else + { + ERR("Index buffer not initialized."); + return false; + } +} + +bool IndexBuffer9::unmapBuffer() +{ + if (mIndexBuffer) + { + HRESULT result = mIndexBuffer->Unlock(); + if (FAILED(result)) + { + ERR("Index buffer unlock failed with error 0x%08x", result); + return false; + } + + return true; + } + else + { + ERR("Index buffer not initialized."); + return false; + } +} + +GLenum IndexBuffer9::getIndexType() const +{ + return mIndexType; +} + +unsigned int IndexBuffer9::getBufferSize() const +{ + return mBufferSize; +} + +bool IndexBuffer9::setSize(unsigned int bufferSize, GLenum indexType) +{ + if (bufferSize > mBufferSize || indexType != mIndexType) + { + return initialize(bufferSize, indexType, mDynamic); + } + else + { + return true; + } +} + +bool IndexBuffer9::discard() +{ + if (mIndexBuffer) + { + void *dummy; + HRESULT result; + + result = mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); + if (FAILED(result)) + { + ERR("Discard lock failed with error 0x%08x", result); + return false; + } + + result = mIndexBuffer->Unlock(); + if (FAILED(result)) + { + ERR("Discard unlock failed with error 0x%08x", result); + return false; + } + + return true; + } + else + { + ERR("Index buffer not initialized."); + return false; + } +} + +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; +} + +}
\ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h new file mode 100644 index 0000000000..cfc20e1c64 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h @@ -0,0 +1,53 @@ +// +// 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 LIBGLESV2_RENDERER_INDEXBUFFER9_H_ +#define LIBGLESV2_RENDERER_INDEXBUFFER9_H_ + +#include "libGLESv2/renderer/d3d/IndexBuffer.h" + +namespace rx +{ +class Renderer9; + +class IndexBuffer9 : public IndexBuffer +{ + public: + explicit IndexBuffer9(Renderer9 *const renderer); + virtual ~IndexBuffer9(); + + virtual bool initialize(unsigned int bufferSize, GLenum indexType, bool dynamic); + + static IndexBuffer9 *makeIndexBuffer9(IndexBuffer *indexBuffer); + + virtual bool mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory); + virtual bool unmapBuffer(); + + virtual GLenum getIndexType() const; + virtual unsigned int getBufferSize() const; + virtual bool setSize(unsigned int bufferSize, GLenum indexType); + + virtual bool discard(); + + D3DFORMAT getIndexFormat() const; + IDirect3DIndexBuffer9 *getBuffer() const; + + private: + DISALLOW_COPY_AND_ASSIGN(IndexBuffer9); + + rx::Renderer9 *const mRenderer; + + IDirect3DIndexBuffer9 *mIndexBuffer; + unsigned int mBufferSize; + GLenum mIndexType; + bool mDynamic; +}; + +} + +#endif // LIBGLESV2_RENDERER_INDEXBUFFER9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.cpp new file mode 100644 index 0000000000..3c6f1d0d43 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.cpp @@ -0,0 +1,125 @@ +#include "precompiled.h" +// +// 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 "libGLESv2/renderer/d3d/d3d9/Query9.h" +#include "libGLESv2/main.h" +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ + +Query9::Query9(rx::Renderer9 *renderer, GLenum type) : QueryImpl(type) +{ + mRenderer = renderer; + mQuery = NULL; +} + +Query9::~Query9() +{ + SafeRelease(mQuery); +} + +void Query9::begin() +{ + if (mQuery == NULL) + { + if (FAILED(mRenderer->getDevice()->CreateQuery(D3DQUERYTYPE_OCCLUSION, &mQuery))) + { + return gl::error(GL_OUT_OF_MEMORY); + } + } + + HRESULT result = mQuery->Issue(D3DISSUE_BEGIN); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); +} + +void Query9::end() +{ + ASSERT(mQuery); + + HRESULT result = mQuery->Issue(D3DISSUE_END); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + mStatus = GL_FALSE; + mResult = GL_FALSE; +} + +GLuint Query9::getResult() +{ + if (mQuery != NULL) + { + while (!testQuery()) + { + Sleep(0); + // 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 (mRenderer->testDeviceLost(true)) + { + return gl::error(GL_OUT_OF_MEMORY, 0); + } + } + } + + return mResult; +} + +GLboolean Query9::isResultAvailable() +{ + if (mQuery != NULL) + { + testQuery(); + } + + return mStatus; +} + +GLboolean Query9::testQuery() +{ + if (mQuery != NULL && mStatus != GL_TRUE) + { + DWORD numPixels = 0; + + HRESULT hres = mQuery->GetData(&numPixels, sizeof(DWORD), D3DGETDATA_FLUSH); + if (hres == S_OK) + { + mStatus = GL_TRUE; + + switch (getType()) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + break; + default: + ASSERT(false); + } + } + else if (d3d9::isDeviceLostError(hres)) + { + mRenderer->notifyDeviceLost(); + return gl::error(GL_OUT_OF_MEMORY, GL_TRUE); + } + + return mStatus; + } + + return GL_TRUE; // prevent blocking when query is null +} + +bool Query9::isStarted() const +{ + return (mQuery != NULL); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.h new file mode 100644 index 0000000000..62906230c4 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.h @@ -0,0 +1,41 @@ +// +// 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 LIBGLESV2_RENDERER_QUERY9_H_ +#define LIBGLESV2_RENDERER_QUERY9_H_ + +#include "libGLESv2/renderer/QueryImpl.h" + +namespace rx +{ +class Renderer9; + +class Query9 : public QueryImpl +{ + public: + Query9(rx::Renderer9 *renderer, GLenum type); + virtual ~Query9(); + + virtual void begin(); + virtual void end(); + virtual GLuint getResult(); + virtual GLboolean isResultAvailable(); + virtual bool isStarted() const; + + private: + DISALLOW_COPY_AND_ASSIGN(Query9); + + GLboolean testQuery(); + + rx::Renderer9 *mRenderer; + IDirect3DQuery9 *mQuery; +}; + +} + +#endif // LIBGLESV2_RENDERER_QUERY9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp new file mode 100644 index 0000000000..49bd9b4000 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp @@ -0,0 +1,139 @@ +#include "precompiled.h" +// +// 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 "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" + +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/main.h" + +namespace rx +{ + +// TODO: AddRef the incoming surface to take ownership instead of expecting that its ref is being given. +RenderTarget9::RenderTarget9(Renderer *renderer, IDirect3DSurface9 *surface) +{ + mRenderer = Renderer9::makeRenderer9(renderer); + mRenderTarget = surface; + + if (mRenderTarget) + { + D3DSURFACE_DESC description; + mRenderTarget->GetDesc(&description); + + mWidth = description.Width; + mHeight = description.Height; + mDepth = 1; + + mInternalFormat = d3d9_gl::GetInternalFormat(description.Format); + mActualFormat = d3d9_gl::GetInternalFormat(description.Format); + mSamples = d3d9_gl::GetSamplesCount(description.MultiSampleType); + } +} + +RenderTarget9::RenderTarget9(Renderer *renderer, GLsizei width, GLsizei height, GLenum internalFormat, GLsizei samples) +{ + mRenderer = Renderer9::makeRenderer9(renderer); + mRenderTarget = NULL; + + D3DFORMAT renderFormat = gl_d3d9::GetRenderFormat(internalFormat); + int supportedSamples = mRenderer->getNearestSupportedSamples(renderFormat, samples); + + if (supportedSamples == -1) + { + gl::error(GL_OUT_OF_MEMORY); + + return; + } + + HRESULT result = D3DERR_INVALIDCALL; + + if (width > 0 && height > 0) + { + IDirect3DDevice9 *device = mRenderer->getDevice(); + + bool requiresInitialization = false; + + if (gl::GetDepthBits(internalFormat) > 0 || + gl::GetStencilBits(internalFormat) > 0) + { + result = device->CreateDepthStencilSurface(width, height, renderFormat, + gl_d3d9::GetMultisampleType(supportedSamples), + 0, FALSE, &mRenderTarget, NULL); + } + else + { + requiresInitialization = gl_d3d9::RequiresTextureDataInitialization(internalFormat); + + result = device->CreateRenderTarget(width, height, renderFormat, + gl_d3d9::GetMultisampleType(supportedSamples), + 0, FALSE, &mRenderTarget, NULL); + } + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + gl::error(GL_OUT_OF_MEMORY); + + return; + } + + ASSERT(SUCCEEDED(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; + device->GetRenderTarget(0, &prevRenderTarget); + device->SetRenderTarget(0, mRenderTarget); + device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 0.0f, 0); + device->SetRenderTarget(0, prevRenderTarget); + } + } + + mWidth = width; + mHeight = height; + mDepth = 1; + mInternalFormat = internalFormat; + mSamples = supportedSamples; + mActualFormat = d3d9_gl::GetInternalFormat(renderFormat); +} + +RenderTarget9::~RenderTarget9() +{ + SafeRelease(mRenderTarget); +} + +RenderTarget9 *RenderTarget9::makeRenderTarget9(RenderTarget *target) +{ + ASSERT(HAS_DYNAMIC_TYPE(rx::RenderTarget9*, target)); + return static_cast<rx::RenderTarget9*>(target); +} + +void RenderTarget9::invalidate(GLint x, GLint y, GLsizei width, GLsizei height) +{ + // Currently a no-op +} + +IDirect3DSurface9 *RenderTarget9::getSurface() +{ + // Caller is responsible for releasing the returned surface reference. + // TODO: remove the AddRef to match RenderTarget11 + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + return mRenderTarget; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.h new file mode 100644 index 0000000000..68d7adb49e --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.h @@ -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. +// + +// RenderTarget9.h: Defines a D3D9-specific wrapper for IDirect3DSurface9 pointers +// retained by Renderbuffers. + +#ifndef LIBGLESV2_RENDERER_RENDERTARGET9_H_ +#define LIBGLESV2_RENDERER_RENDERTARGET9_H_ + +#include "libGLESv2/renderer/RenderTarget.h" + +namespace rx +{ +class Renderer; +class Renderer9; + +class RenderTarget9 : public RenderTarget +{ + public: + RenderTarget9(Renderer *renderer, IDirect3DSurface9 *surface); + RenderTarget9(Renderer *renderer, GLsizei width, GLsizei height, GLenum internalFormat, GLsizei samples); + virtual ~RenderTarget9(); + + static RenderTarget9 *makeRenderTarget9(RenderTarget *renderTarget); + + virtual void invalidate(GLint x, GLint y, GLsizei width, GLsizei height); + + IDirect3DSurface9 *getSurface(); + + private: + DISALLOW_COPY_AND_ASSIGN(RenderTarget9); + + IDirect3DSurface9 *mRenderTarget; + + Renderer9 *mRenderer; +}; + +} + +#endif // LIBGLESV2_RENDERER_RENDERTARGET9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp new file mode 100644 index 0000000000..491c27a6ab --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp @@ -0,0 +1,3254 @@ +#include "precompiled.h" +// +// 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 "common/utilities.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/Buffer.h" +#include "libGLESv2/Texture.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" +#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/renderer/d3d/IndexDataManager.h" +#include "libGLESv2/renderer/d3d/TextureD3D.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.h" +#include "libGLESv2/renderer/d3d/d3d9/SwapChain9.h" +#include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h" +#include "libGLESv2/renderer/d3d/d3d9/Image9.h" +#include "libGLESv2/renderer/d3d/d3d9/Blit9.h" +#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" +#include "libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h" +#include "libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h" +#include "libGLESv2/renderer/d3d/d3d9/Buffer9.h" +#include "libGLESv2/renderer/d3d/d3d9/Query9.h" +#include "libGLESv2/renderer/d3d/d3d9/Fence9.h" +#include "libGLESv2/renderer/d3d/d3d9/VertexArray9.h" +#include "libGLESv2/angletypes.h" + +#include "libEGL/Display.h" + +#include "third_party/trace_event/trace_event.h" + +// Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros +#define REF_RAST 0 + +// The "Debug This Pixel..." feature in PIX often fails when using the +// D3D9Ex interfaces. In order to get debug pixel to work on a Vista/Win 7 +// machine, define "ANGLE_ENABLE_D3D9EX=0" in your project file. +#if !defined(ANGLE_ENABLE_D3D9EX) +// Enables use of the IDirect3D9Ex interface, when available +#define ANGLE_ENABLE_D3D9EX 1 +#endif // !defined(ANGLE_ENABLE_D3D9EX) + +#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL) +#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3 +#endif + +const D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I','N','T','Z'))); +const D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N','U','L','L'))); + +namespace rx +{ +static const D3DFORMAT RenderTargetFormats[] = + { + D3DFMT_A1R5G5B5, + // D3DFMT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value. + D3DFMT_A8R8G8B8, + D3DFMT_R5G6B5, + // D3DFMT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format + D3DFMT_X8R8G8B8 + }; + +static const D3DFORMAT DepthStencilFormats[] = + { + D3DFMT_UNKNOWN, + // D3DFMT_D16_LOCKABLE, + D3DFMT_D32, + // D3DFMT_D15S1, + D3DFMT_D24S8, + D3DFMT_D24X8, + // D3DFMT_D24X4S4, + D3DFMT_D16, + // D3DFMT_D32F_LOCKABLE, + // D3DFMT_D24FS8 + }; + +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, EGLNativeDisplayType hDc, EGLint requestedDisplay) + : Renderer(display), + mDc(hDc) +{ + mD3d9Module = NULL; + + mD3d9 = NULL; + mD3d9Ex = NULL; + mDevice = NULL; + mDeviceEx = NULL; + mDeviceWindow = NULL; + mBlit = NULL; + + mAdapter = D3DADAPTER_DEFAULT; + + #if REF_RAST == 1 || defined(FORCE_REF_RAST) + mDeviceType = D3DDEVTYPE_REF; + #else + mDeviceType = D3DDEVTYPE_HAL; + #endif + + mDeviceLost = false; + + mMaxSupportedSamples = 0; + + mMaskedClearSavedState = NULL; + + mVertexDataManager = NULL; + mIndexDataManager = NULL; + mLineLoopIB = 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; +} + +Renderer9::~Renderer9() +{ + if (mDevice) + { + // If the device is lost, reset it first to prevent leaving the driver in an unstable state + if (testDeviceLost(false)) + { + resetDevice(); + } + } + + release(); +} + +void Renderer9::release() +{ + releaseDeviceResources(); + + SafeRelease(mDevice); + SafeRelease(mDeviceEx); + SafeRelease(mD3d9); + SafeRelease(mD3d9Ex); + + mCompiler.release(); + + if (mDeviceWindow) + { + DestroyWindow(mDeviceWindow); + mDeviceWindow = NULL; + } + + mD3d9Module = NULL; +} + +Renderer9 *Renderer9::makeRenderer9(Renderer *renderer) +{ + ASSERT(HAS_DYNAMIC_TYPE(rx::Renderer9*, renderer)); + return static_cast<rx::Renderer9*>(renderer); +} + +EGLint Renderer9::initialize() +{ + if (!mCompiler.initialize()) + { + return EGL_NOT_INITIALIZED; + } + + TRACE_EVENT0("gpu", "GetModuleHandle_d3d9"); + mD3d9Module = GetModuleHandle(TEXT("d3d9.dll")); + + if (mD3d9Module == NULL) + { + ERR("No D3D9 module found - aborting!\n"); + return EGL_NOT_INITIALIZED; + } + + 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_ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex))) + { + TRACE_EVENT0("gpu", "D3d9Ex_QueryInterface"); + ASSERT(mD3d9Ex); + mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast<void**>(&mD3d9)); + ASSERT(mD3d9); + } + else + { + TRACE_EVENT0("gpu", "Direct3DCreate9"); + mD3d9 = Direct3DCreate9(D3D_SDK_VERSION); + } + + if (!mD3d9) + { + ERR("Could not create D3D9 device - aborting!\n"); + return EGL_NOT_INITIALIZED; + } + + if (mDc != NULL) + { + // 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", "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 + { + ERR("failed to get device caps (0x%x)\n", result); + return EGL_NOT_INITIALIZED; + } + } + } + + if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0)) + { + ERR("Renderer does not support PS 2.0. aborting!\n"); + return EGL_NOT_INITIALIZED; + } + + // 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) + { + ERR("Renderer does not support stretctrect from textures!\n"); + return EGL_NOT_INITIALIZED; + } + + { + TRACE_EVENT0("gpu", "GetAdapterIdentifier"); + mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier); + } + + mMinSwapInterval = 4; + mMaxSwapInterval = 0; + + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) + { + mMinSwapInterval = std::min(mMinSwapInterval, 0); + mMaxSwapInterval = std::max(mMaxSwapInterval, 0); + } + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE) + { + mMinSwapInterval = std::min(mMinSwapInterval, 1); + mMaxSwapInterval = std::max(mMaxSwapInterval, 1); + } + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO) + { + mMinSwapInterval = std::min(mMinSwapInterval, 2); + mMaxSwapInterval = std::max(mMaxSwapInterval, 2); + } + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE) + { + mMinSwapInterval = std::min(mMinSwapInterval, 3); + mMaxSwapInterval = std::max(mMaxSwapInterval, 3); + } + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR) + { + mMinSwapInterval = std::min(mMinSwapInterval, 4); + mMaxSwapInterval = std::max(mMaxSwapInterval, 4); + } + + mMaxSupportedSamples = 0; + + const d3d9::D3DFormatSet &d3d9Formats = d3d9::GetAllUsedD3DFormats(); + for (d3d9::D3DFormatSet::const_iterator i = d3d9Formats.begin(); i != d3d9Formats.end(); ++i) + { + TRACE_EVENT0("gpu", "getMultiSampleSupport"); + MultisampleSupportInfo support = getMultiSampleSupport(*i); + mMultiSampleSupport[*i] = support; + mMaxSupportedSamples = std::max(mMaxSupportedSamples, support.maxSupportedSamples); + } + + static const TCHAR windowName[] = TEXT("AngleHiddenWindow"); + static const TCHAR className[] = TEXT("STATIC"); + + { + TRACE_EVENT0("gpu", "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; + + { + TRACE_EVENT0("gpu", "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_BAD_ALLOC; + } + + if (FAILED(result)) + { + TRACE_EVENT0("gpu", "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_BAD_ALLOC; + } + } + + if (mD3d9Ex) + { + TRACE_EVENT0("gpu", "mDevice_QueryInterface"); + result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**)&mDeviceEx); + ASSERT(SUCCEEDED(result)); + } + + { + TRACE_EVENT0("gpu", "ShaderCache initialize"); + mVertexShaderCache.initialize(mDevice); + mPixelShaderCache.initialize(mDevice); + } + + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + // 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(); + + d3d9::InitializeVertexTranslations(this); + + return 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 + } + + markAllStateDirty(); + + mSceneStarted = false; + + ASSERT(!mBlit && !mVertexDataManager && !mIndexDataManager); + mBlit = new Blit9(this); + mVertexDataManager = new rx::VertexDataManager(this); + mIndexDataManager = new rx::IndexDataManager(this); +} + +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; +} + +int Renderer9::generateConfigs(ConfigDesc **configDescList) +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + unsigned int numRenderFormats = ArraySize(RenderTargetFormats); + unsigned int numDepthFormats = ArraySize(DepthStencilFormats); + (*configDescList) = new ConfigDesc[numRenderFormats * numDepthFormats]; + int numConfigs = 0; + + for (unsigned int formatIndex = 0; formatIndex < numRenderFormats; formatIndex++) + { + D3DFORMAT renderTargetFormat = RenderTargetFormats[formatIndex]; + + HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, renderTargetFormat); + + if (SUCCEEDED(result)) + { + for (unsigned int depthStencilIndex = 0; depthStencilIndex < numDepthFormats; depthStencilIndex++) + { + D3DFORMAT depthStencilFormat = DepthStencilFormats[depthStencilIndex]; + HRESULT result = D3D_OK; + + if(depthStencilFormat != D3DFMT_UNKNOWN) + { + result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, depthStencilFormat); + } + + if (SUCCEEDED(result)) + { + if(depthStencilFormat != D3DFMT_UNKNOWN) + { + result = mD3d9->CheckDepthStencilMatch(mAdapter, mDeviceType, currentDisplayMode.Format, renderTargetFormat, depthStencilFormat); + } + + if (SUCCEEDED(result)) + { + ConfigDesc newConfig; + newConfig.renderTargetFormat = d3d9_gl::GetInternalFormat(renderTargetFormat); + newConfig.depthStencilFormat = d3d9_gl::GetInternalFormat(depthStencilFormat); + newConfig.multiSample = 0; // FIXME: enumerate multi-sampling + newConfig.fastConfig = (currentDisplayMode.Format == renderTargetFormat); + newConfig.es3Capable = false; + + (*configDescList)[numConfigs++] = newConfig; + } + } + } + } + } + + return numConfigs; +} + +void Renderer9::deleteConfigs(ConfigDesc *configDescList) +{ + delete [] (configDescList); +} + +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; + } +} + +void Renderer9::sync(bool block) +{ + HRESULT result; + + IDirect3DQuery9* query = allocateEventQuery(); + if (!query) + { + return; + } + + result = query->Issue(D3DISSUE_END); + ASSERT(SUCCEEDED(result)); + + do + { + result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); + + if(block && result == S_FALSE) + { + // Keep polling, but allow other threads to do something useful first + Sleep(0); + // 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 (testDeviceLost(false)) + { + result = D3DERR_DEVICELOST; + } + } + } + while(block && result == S_FALSE); + + freeEventQuery(query); + + if (d3d9::isDeviceLostError(result)) + { + notifyDeviceLost(); + } +} + +SwapChain *Renderer9::createSwapChain(HWND window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) +{ + return new rx::SwapChain9(this, window, shareHandle, backBufferFormat, depthBufferFormat); +} + +IDirect3DQuery9* Renderer9::allocateEventQuery() +{ + IDirect3DQuery9 *query = NULL; + + if (mEventQueryPool.empty()) + { + HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + } + else + { + query = mEventQueryPool.back(); + mEventQueryPool.pop_back(); + } + + return query; +} + +void Renderer9::freeEventQuery(IDirect3DQuery9* query) +{ + if (mEventQueryPool.size() > 1000) + { + SafeRelease(query); + } + else + { + mEventQueryPool.push_back(query); + } +} + +IDirect3DVertexShader9 *Renderer9::createVertexShader(const DWORD *function, size_t length) +{ + return mVertexShaderCache.create(function, length); +} + +IDirect3DPixelShader9 *Renderer9::createPixelShader(const DWORD *function, size_t length) +{ + return mPixelShaderCache.create(function, length); +} + +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); +} + +BufferImpl *Renderer9::createBuffer() +{ + return new Buffer9(this); +} + +VertexArrayImpl *Renderer9::createVertexArray() +{ + return new VertexArray9(this); +} + +QueryImpl *Renderer9::createQuery(GLenum type) +{ + return new Query9(this, type); +} + +FenceImpl *Renderer9::createFence() +{ + return new Fence9(this); +} + +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; +} + +bool Renderer9::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *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 false; +} + +void Renderer9::generateSwizzle(gl::Texture *texture) +{ + // Swizzled textures are not available in ES2 or D3D9 + UNREACHABLE(); +} + +void Renderer9::setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &samplerState) +{ + bool *forceSetSamplers = (type == gl::SAMPLER_PIXEL) ? mForceSetPixelSamplerStates : mForceSetVertexSamplerStates; + gl::SamplerState *appliedSamplers = (type == gl::SAMPLER_PIXEL) ? mCurPixelSamplerStates: mCurVertexSamplerStates; + + if (forceSetSamplers[index] || memcmp(&samplerState, &appliedSamplers[index], 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; + gl_d3d9::ConvertMinFilter(samplerState.minFilter, &d3dMinFilter, &d3dMipFilter, samplerState.maxAnisotropy); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, samplerState.baseLevel); + if (getRendererExtensions().textureFilterAnisotropic) + { + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)samplerState.maxAnisotropy); + } + } + + forceSetSamplers[index] = false; + appliedSamplers[index] = samplerState; +} + +void 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; + unsigned int serial = 0; + bool forceSetTexture = false; + + unsigned int *appliedSerials = (type == gl::SAMPLER_PIXEL) ? mCurPixelTextureSerials : mCurVertexTextureSerials; + + if (texture) + { + TextureStorageInterface *texStorage = texture->getNativeTexture(); + if (texStorage) + { + TextureStorage9 *storage9 = TextureStorage9::makeTextureStorage9(texStorage->getStorageInstance()); + d3dTexture = storage9->getBaseTexture(); + } + // 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); + + serial = texture->getTextureSerial(); + forceSetTexture = texture->hasDirtyImages(); + } + + if (forceSetTexture || appliedSerials[index] != serial) + { + mDevice->SetTexture(d3dSampler, d3dTexture); + } + + appliedSerials[index] = serial; +} + +bool Renderer9::setUniformBuffers(const gl::Buffer* /*vertexUniformBuffers*/[], const gl::Buffer* /*fragmentUniformBuffers*/[]) +{ + // No effect in ES2/D3D9 + return true; +} + +void Renderer9::setRasterizerState(const gl::RasterizerState &rasterState) +{ + bool rasterStateChanged = mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0; + + if (rasterStateChanged) + { + // Set the cull mode + if (rasterState.cullFace) + { + mDevice->SetRenderState(D3DRS_CULLMODE, gl_d3d9::ConvertCullMode(rasterState.cullMode, rasterState.frontFace)); + } + else + { + mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + } + + if (rasterState.polygonOffsetFill) + { + if (mCurDepthSize > 0) + { + mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&rasterState.polygonOffsetFactor); + + float depthBias = ldexp(rasterState.polygonOffsetUnits, -static_cast<int>(mCurDepthSize)); + mDevice->SetRenderState(D3DRS_DEPTHBIAS, *(DWORD*)&depthBias); + } + } + else + { + mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0); + mDevice->SetRenderState(D3DRS_DEPTHBIAS, 0); + } + + mCurRasterState = rasterState; + } + + mForceSetRasterState = false; +} + +void Renderer9::setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask) +{ + bool blendStateChanged = mForceSetBlendState || memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0; + bool blendColorChanged = mForceSetBlendState || memcmp(&blendColor, &mCurBlendColor, sizeof(gl::ColorF)) != 0; + bool sampleMaskChanged = mForceSetBlendState || sampleMask != mCurSampleMask; + + if (blendStateChanged || blendColorChanged) + { + if (blendState.blend) + { + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + + 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) + { + mDevice->SetRenderState(D3DRS_BLENDFACTOR, gl_d3d9::ConvertColor(blendColor)); + } + else + { + mDevice->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))); + } + + mDevice->SetRenderState(D3DRS_SRCBLEND, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendRGB)); + mDevice->SetRenderState(D3DRS_DESTBLEND, gl_d3d9::ConvertBlendFunc(blendState.destBlendRGB)); + mDevice->SetRenderState(D3DRS_BLENDOP, gl_d3d9::ConvertBlendOp(blendState.blendEquationRGB)); + + if (blendState.sourceBlendRGB != blendState.sourceBlendAlpha || + blendState.destBlendRGB != blendState.destBlendAlpha || + blendState.blendEquationRGB != blendState.blendEquationAlpha) + { + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + + mDevice->SetRenderState(D3DRS_SRCBLENDALPHA, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendAlpha)); + mDevice->SetRenderState(D3DRS_DESTBLENDALPHA, gl_d3d9::ConvertBlendFunc(blendState.destBlendAlpha)); + mDevice->SetRenderState(D3DRS_BLENDOPALPHA, gl_d3d9::ConvertBlendOp(blendState.blendEquationAlpha)); + } + else + { + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); + } + } + else + { + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + } + + if (blendState.sampleAlphaToCoverage) + { + FIXME("Sample alpha to coverage is unimplemented."); + } + + gl::FramebufferAttachment *attachment = framebuffer->getFirstColorbuffer(); + GLenum internalFormat = attachment ? attachment->getInternalFormat() : GL_NONE; + + // Set the color mask + bool zeroColorMaskAllowed = getAdapterVendor() != VENDOR_ID_AMD; + // 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://code.google.com/p/angleproject/issues/detail?id=169 + + DWORD colorMask = gl_d3d9::ConvertColorMask(gl::GetRedBits(internalFormat) > 0 && blendState.colorMaskRed, + gl::GetGreenBits(internalFormat) > 0 && blendState.colorMaskGreen, + gl::GetBlueBits(internalFormat) > 0 && blendState.colorMaskBlue, + gl::GetAlphaBits(internalFormat) > 0 && blendState.colorMaskAlpha); + if (colorMask == 0 && !zeroColorMaskAllowed) + { + // Enable green channel, but set blending so nothing will be drawn. + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN); + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + + mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); + mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + } + else + { + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask); + } + + mDevice->SetRenderState(D3DRS_DITHERENABLE, blendState.dither ? TRUE : FALSE); + + mCurBlendState = blendState; + mCurBlendColor = blendColor; + } + + if (sampleMaskChanged) + { + // Set the multisample mask + mDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, static_cast<DWORD>(sampleMask)); + + mCurSampleMask = sampleMask; + } + + mForceSetBlendState = false; +} + +void Renderer9::setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, + int stencilBackRef, bool frontFaceCCW) +{ + bool depthStencilStateChanged = mForceSetDepthStencilState || + memcmp(&depthStencilState, &mCurDepthStencilState, sizeof(gl::DepthStencilState)) != 0; + bool stencilRefChanged = mForceSetDepthStencilState || stencilRef != mCurStencilRef || + stencilBackRef != mCurStencilBackRef; + bool frontFaceCCWChanged = mForceSetDepthStencilState || frontFaceCCW != mCurFrontFaceCCW; + + if (depthStencilStateChanged) + { + if (depthStencilState.depthTest) + { + mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); + mDevice->SetRenderState(D3DRS_ZFUNC, gl_d3d9::ConvertComparison(depthStencilState.depthFunc)); + } + else + { + mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + } + + mCurDepthStencilState = depthStencilState; + } + + if (depthStencilStateChanged || stencilRefChanged || frontFaceCCWChanged) + { + if (depthStencilState.stencilTest && mCurStencilSize > 0) + { + mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE); + mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE); + + // FIXME: Unsupported by D3D9 + const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF; + const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK; + const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK; + + ASSERT(depthStencilState.stencilWritemask == depthStencilState.stencilBackWritemask); + ASSERT(stencilRef == stencilBackRef); + ASSERT(depthStencilState.stencilMask == depthStencilState.stencilBackMask); + + // get the maximum size of the stencil ref + unsigned int maxStencil = (1 << mCurStencilSize) - 1; + + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, + depthStencilState.stencilWritemask); + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, + gl_d3d9::ConvertComparison(depthStencilState.stencilFunc)); + + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, + (stencilRef < (int)maxStencil) ? stencilRef : maxStencil); + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, + depthStencilState.stencilMask); + + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilFail)); + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilPassDepthFail)); + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilPassDepthPass)); + + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, + depthStencilState.stencilBackWritemask); + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, + gl_d3d9::ConvertComparison(depthStencilState.stencilBackFunc)); + + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, + (stencilBackRef < (int)maxStencil) ? stencilBackRef : maxStencil); + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, + depthStencilState.stencilBackMask); + + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackFail)); + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackPassDepthFail)); + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackPassDepthPass)); + } + else + { + mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + } + + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, depthStencilState.depthMask ? TRUE : FALSE); + + mCurStencilRef = stencilRef; + mCurStencilBackRef = stencilBackRef; + mCurFrontFaceCCW = frontFaceCCW; + } + + mForceSetDepthStencilState = false; +} + +void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) +{ + bool scissorChanged = mForceSetScissor || + memcmp(&scissor, &mCurScissor, sizeof(gl::Rectangle)) != 0 || + enabled != mScissorEnabled; + + if (scissorChanged) + { + if (enabled) + { + RECT rect; + rect.left = gl::clamp(scissor.x, 0, static_cast<int>(mRenderTargetDesc.width)); + rect.top = gl::clamp(scissor.y, 0, static_cast<int>(mRenderTargetDesc.height)); + rect.right = gl::clamp(scissor.x + scissor.width, 0, static_cast<int>(mRenderTargetDesc.width)); + rect.bottom = gl::clamp(scissor.y + scissor.height, 0, static_cast<int>(mRenderTargetDesc.height)); + mDevice->SetScissorRect(&rect); + } + + mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, enabled ? TRUE : FALSE); + + mScissorEnabled = enabled; + mCurScissor = scissor; + } + + mForceSetScissor = false; +} + +bool Renderer9::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, + bool ignoreViewport) +{ + gl::Rectangle actualViewport = viewport; + float actualZNear = gl::clamp01(zNear); + float actualZFar = gl::clamp01(zFar); + if (ignoreViewport) + { + actualViewport.x = 0; + actualViewport.y = 0; + actualViewport.width = mRenderTargetDesc.width; + actualViewport.height = mRenderTargetDesc.height; + actualZNear = 0.0f; + actualZFar = 1.0f; + } + + D3DVIEWPORT9 dxViewport; + dxViewport.X = gl::clamp(actualViewport.x, 0, static_cast<int>(mRenderTargetDesc.width)); + dxViewport.Y = gl::clamp(actualViewport.y, 0, static_cast<int>(mRenderTargetDesc.height)); + dxViewport.Width = gl::clamp(actualViewport.width, 0, static_cast<int>(mRenderTargetDesc.width) - static_cast<int>(dxViewport.X)); + dxViewport.Height = gl::clamp(actualViewport.height, 0, static_cast<int>(mRenderTargetDesc.height) - static_cast<int>(dxViewport.Y)); + dxViewport.MinZ = actualZNear; + dxViewport.MaxZ = actualZFar; + + if (dxViewport.Width <= 0 || dxViewport.Height <= 0) + { + return false; // Nothing to render + } + + float depthFront = !gl::IsTriangleMode(drawMode) ? 0.0f : (frontFace == GL_CCW ? 1.0f : -1.0f); + + bool viewportChanged = mForceSetViewport || memcmp(&actualViewport, &mCurViewport, sizeof(gl::Rectangle)) != 0 || + actualZNear != mCurNear || actualZFar != mCurFar || mCurDepthFront != depthFront; + if (viewportChanged) + { + mDevice->SetViewport(&dxViewport); + + mCurViewport = actualViewport; + mCurNear = actualZNear; + mCurFar = actualZFar; + mCurDepthFront = depthFront; + + dx_VertexConstants vc = {0}; + dx_PixelConstants pc = {0}; + + vc.viewAdjust[0] = (float)((actualViewport.width - (int)dxViewport.Width) + 2 * (actualViewport.x - (int)dxViewport.X) - 1) / dxViewport.Width; + vc.viewAdjust[1] = (float)((actualViewport.height - (int)dxViewport.Height) + 2 * (actualViewport.y - (int)dxViewport.Y) - 1) / dxViewport.Height; + vc.viewAdjust[2] = (float)actualViewport.width / dxViewport.Width; + vc.viewAdjust[3] = (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_VertexConstants)) != 0) + { + mVertexConstants = vc; + mDxUniformsDirty = true; + } + + if (memcmp(&pc, &mPixelConstants, sizeof(dx_PixelConstants)) != 0) + { + mPixelConstants = pc; + mDxUniformsDirty = true; + } + } + + mForceSetViewport = false; + return true; +} + +bool Renderer9::applyPrimitiveType(GLenum mode, GLsizei count) +{ + 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::FramebufferAttachment *Renderer9::getNullColorbuffer(gl::FramebufferAttachment *depthbuffer) +{ + if (!depthbuffer) + { + ERR("Unexpected null depthbuffer for depth-only FBO."); + return NULL; + } + + GLsizei width = depthbuffer->getWidth(); + GLsizei height = depthbuffer->getHeight(); + + // search cached nullcolorbuffers + for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) + { + if (mNullColorbufferCache[i].buffer != NULL && + mNullColorbufferCache[i].width == width && + mNullColorbufferCache[i].height == height) + { + mNullColorbufferCache[i].lruCount = ++mMaxNullColorbufferLRU; + return mNullColorbufferCache[i].buffer; + } + } + + gl::Renderbuffer *nullRenderbuffer = new gl::Renderbuffer(0, new gl::Colorbuffer(this, width, height, GL_NONE, 0)); + gl::RenderbufferAttachment *nullbuffer = new gl::RenderbufferAttachment(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 = width; + oldest->height = height; + + return nullbuffer; +} + +bool Renderer9::applyRenderTarget(gl::Framebuffer *framebuffer) +{ + // 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. + gl::FramebufferAttachment *attachment = framebuffer->getColorbuffer(0); + if (!attachment) + { + attachment = getNullColorbuffer(framebuffer->getDepthbuffer()); + } + if (!attachment) + { + ERR("unable to locate renderbuffer for FBO."); + return false; + } + + bool renderTargetChanged = false; + unsigned int renderTargetSerial = attachment->getSerial(); + if (renderTargetSerial != mAppliedRenderTargetSerial) + { + // Apply the render target on the device + IDirect3DSurface9 *renderTargetSurface = NULL; + + RenderTarget *renderTarget = attachment->getRenderTarget(); + if (renderTarget) + { + renderTargetSurface = RenderTarget9::makeRenderTarget9(renderTarget)->getSurface(); + } + + if (!renderTargetSurface) + { + ERR("render target pointer unexpectedly null."); + return false; // Context must be lost + } + + mDevice->SetRenderTarget(0, renderTargetSurface); + SafeRelease(renderTargetSurface); + + mAppliedRenderTargetSerial = renderTargetSerial; + renderTargetChanged = true; + } + + gl::FramebufferAttachment *depthStencil = framebuffer->getDepthbuffer(); + unsigned int depthbufferSerial = 0; + unsigned int stencilbufferSerial = 0; + if (depthStencil) + { + depthbufferSerial = depthStencil->getSerial(); + } + else if (framebuffer->getStencilbuffer()) + { + depthStencil = framebuffer->getStencilbuffer(); + stencilbufferSerial = depthStencil->getSerial(); + } + + if (depthbufferSerial != mAppliedDepthbufferSerial || + stencilbufferSerial != mAppliedStencilbufferSerial || + !mDepthStencilInitialized) + { + unsigned int depthSize = 0; + unsigned int stencilSize = 0; + + // Apply the depth stencil on the device + if (depthStencil) + { + IDirect3DSurface9 *depthStencilSurface = NULL; + RenderTarget *depthStencilRenderTarget = depthStencil->getDepthStencil(); + + if (depthStencilRenderTarget) + { + depthStencilSurface = RenderTarget9::makeRenderTarget9(depthStencilRenderTarget)->getSurface(); + } + + if (!depthStencilSurface) + { + ERR("depth stencil pointer unexpectedly null."); + return false; // Context must be lost + } + + mDevice->SetDepthStencilSurface(depthStencilSurface); + SafeRelease(depthStencilSurface); + + depthSize = depthStencil->getDepthSize(); + stencilSize = depthStencil->getStencilSize(); + } + else + { + mDevice->SetDepthStencilSurface(NULL); + } + + if (!mDepthStencilInitialized || depthSize != mCurDepthSize) + { + mCurDepthSize = depthSize; + mForceSetRasterState = true; + } + + if (!mDepthStencilInitialized || stencilSize != mCurStencilSize) + { + mCurStencilSize = stencilSize; + mForceSetDepthStencilState = true; + } + + mAppliedDepthbufferSerial = depthbufferSerial; + mAppliedStencilbufferSerial = stencilbufferSerial; + mDepthStencilInitialized = true; + } + + if (renderTargetChanged || !mRenderTargetDescInitialized) + { + mForceSetScissor = true; + mForceSetViewport = true; + mForceSetBlendState = true; + + mRenderTargetDesc.width = attachment->getWidth(); + mRenderTargetDesc.height = attachment->getHeight(); + mRenderTargetDesc.format = attachment->getActualFormat(); + mRenderTargetDescInitialized = true; + } + + return true; +} + +GLenum Renderer9::applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], + GLint first, GLsizei count, GLsizei instances) +{ + TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS]; + GLenum err = mVertexDataManager->prepareVertexData(vertexAttributes, currentValues, programBinary, first, count, attributes, instances); + if (err != GL_NO_ERROR) + { + return err; + } + + return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, programBinary, instances, &mRepeatDraw); +} + +// Applies the indices and element array bindings to the Direct3D 9 device +GLenum Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) +{ + GLenum err = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo); + + if (err == GL_NO_ERROR) + { + // Directly binding the storage buffer is not supported for d3d9 + ASSERT(indexInfo->storage == NULL); + + if (indexInfo->serial != mAppliedIBSerial) + { + IndexBuffer9* indexBuffer = IndexBuffer9::makeIndexBuffer9(indexInfo->indexBuffer); + + mDevice->SetIndices(indexBuffer->getBuffer()); + mAppliedIBSerial = indexInfo->serial; + } + } + + return err; +} + +void Renderer9::applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]) +{ + UNREACHABLE(); +} + +void Renderer9::drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) +{ + ASSERT(!transformFeedbackActive); + + startScene(); + + if (mode == GL_LINE_LOOP) + { + drawLineLoop(count, GL_NONE, NULL, 0, NULL); + } + else if (instances > 0) + { + StaticIndexBufferInterface *countingIB = mIndexDataManager->getCountingIndices(count); + if (countingIB) + { + if (mAppliedIBSerial != countingIB->getSerial()) + { + IndexBuffer9 *indexBuffer = IndexBuffer9::makeIndexBuffer9(countingIB->getIndexBuffer()); + + mDevice->SetIndices(indexBuffer->getBuffer()); + mAppliedIBSerial = countingIB->getSerial(); + } + + for (int i = 0; i < mRepeatDraw; i++) + { + mDevice->DrawIndexedPrimitive(mPrimitiveType, 0, 0, count, 0, mPrimitiveCount); + } + } + else + { + ERR("Could not create a counting index buffer for glDrawArraysInstanced."); + return gl::error(GL_OUT_OF_MEMORY); + } + } + else // Regular case + { + mDevice->DrawPrimitive(mPrimitiveType, 0, mPrimitiveCount); + } +} + +void Renderer9::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei /*instances*/) +{ + startScene(); + + if (mode == GL_POINTS) + { + drawIndexedPoints(count, type, indices, indexInfo.minIndex, elementArrayBuffer); + } + else if (mode == GL_LINE_LOOP) + { + drawLineLoop(count, type, indices, indexInfo.minIndex, elementArrayBuffer); + } + else + { + for (int i = 0; i < mRepeatDraw; i++) + { + GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1; + mDevice->DrawIndexedPrimitive(mPrimitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, vertexCount, indexInfo.startIndex, mPrimitiveCount); + } + } +} + +void 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) + { + gl::Buffer *indexBuffer = elementArrayBuffer; + BufferImpl *storage = indexBuffer->getImplementation(); + intptr_t offset = reinterpret_cast<intptr_t>(indices); + indices = static_cast<const GLubyte*>(storage->getData()) + offset; + } + + unsigned int startIndex = 0; + + if (getRendererExtensions().elementIndexUint) + { + if (!mLineLoopIB) + { + mLineLoopIB = new StreamingIndexBufferInterface(this); + if (!mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT)) + { + delete mLineLoopIB; + mLineLoopIB = NULL; + + ERR("Could not create a 32-bit looping index buffer for GL_LINE_LOOP."); + return gl::error(GL_OUT_OF_MEMORY); + } + } + + // Checked by Renderer9::applyPrimitiveType + ASSERT(count >= 0); + + if (static_cast<unsigned int>(count) + 1 > (std::numeric_limits<unsigned int>::max() / sizeof(unsigned int))) + { + ERR("Could not create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); + return gl::error(GL_OUT_OF_MEMORY); + } + + const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * sizeof(unsigned int); + if (!mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT)) + { + ERR("Could not reserve enough space in looping index buffer for GL_LINE_LOOP."); + return gl::error(GL_OUT_OF_MEMORY); + } + + void* mappedMemory = NULL; + unsigned int offset = 0; + if (!mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset)) + { + ERR("Could not map index buffer for GL_LINE_LOOP."); + return gl::error(GL_OUT_OF_MEMORY); + } + + 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(); + } + + if (!mLineLoopIB->unmapBuffer()) + { + ERR("Could not unmap index buffer for GL_LINE_LOOP."); + return gl::error(GL_OUT_OF_MEMORY); + } + } + else + { + if (!mLineLoopIB) + { + mLineLoopIB = new StreamingIndexBufferInterface(this); + if (!mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT)) + { + delete mLineLoopIB; + mLineLoopIB = NULL; + + ERR("Could not create a 16-bit looping index buffer for GL_LINE_LOOP."); + return gl::error(GL_OUT_OF_MEMORY); + } + } + + // Checked by Renderer9::applyPrimitiveType + ASSERT(count >= 0); + + if (static_cast<unsigned int>(count) + 1 > (std::numeric_limits<unsigned short>::max() / sizeof(unsigned short))) + { + ERR("Could not create a 16-bit looping index buffer for GL_LINE_LOOP, too many indices required."); + return gl::error(GL_OUT_OF_MEMORY); + } + + const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * sizeof(unsigned short); + if (!mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT)) + { + ERR("Could not reserve enough space in looping index buffer for GL_LINE_LOOP."); + return gl::error(GL_OUT_OF_MEMORY); + } + + void* mappedMemory = NULL; + unsigned int offset; + if (mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset)) + { + ERR("Could not map index buffer for GL_LINE_LOOP."); + return gl::error(GL_OUT_OF_MEMORY); + } + + 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] = 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(); + } + + if (!mLineLoopIB->unmapBuffer()) + { + ERR("Could not unmap index buffer for GL_LINE_LOOP."); + return gl::error(GL_OUT_OF_MEMORY); + } + } + + if (mAppliedIBSerial != mLineLoopIB->getSerial()) + { + IndexBuffer9 *indexBuffer = IndexBuffer9::makeIndexBuffer9(mLineLoopIB->getIndexBuffer()); + + mDevice->SetIndices(indexBuffer->getBuffer()); + mAppliedIBSerial = mLineLoopIB->getSerial(); + } + + mDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, -minIndex, minIndex, count, startIndex, count); +} + +template <typename T> +static void 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); + } +} + +void 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) + { + BufferImpl *storage = elementArrayBuffer->getImplementation(); + intptr_t offset = reinterpret_cast<intptr_t>(indices); + indices = static_cast<const GLubyte*>(storage->getData()) + offset; + } + + switch (type) + { + case GL_UNSIGNED_BYTE: drawPoints<GLubyte>(mDevice, count, indices, minIndex); break; + case GL_UNSIGNED_SHORT: drawPoints<GLushort>(mDevice, count, indices, minIndex); break; + case GL_UNSIGNED_INT: drawPoints<GLuint>(mDevice, count, indices, minIndex); break; + default: UNREACHABLE(); + } +} + +void Renderer9::applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive) +{ + ASSERT(!transformFeedbackActive); + ASSERT(!rasterizerDiscard); + + ShaderExecutable *vertexExe = programBinary->getVertexExecutableForInputLayout(inputLayout); + ShaderExecutable *pixelExe = programBinary->getPixelExecutableForFramebuffer(framebuffer); + + IDirect3DVertexShader9 *vertexShader = (vertexExe ? ShaderExecutable9::makeShaderExecutable9(vertexExe)->getVertexShader() : NULL); + IDirect3DPixelShader9 *pixelShader = (pixelExe ? ShaderExecutable9::makeShaderExecutable9(pixelExe)->getPixelShader() : NULL); + + 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 = programBinary->getSerial(); + if (programSerial != mAppliedProgramSerial) + { + programBinary->dirtyAllUniforms(); + mDxUniformsDirty = true; + mAppliedProgramSerial = programSerial; + } +} + +void Renderer9::applyUniforms(const gl::ProgramBinary &programBinary) +{ + const std::vector<gl::LinkedUniform*> &uniformArray = programBinary.getUniforms(); + + for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) + { + gl::LinkedUniform *targetUniform = uniformArray[uniformIndex]; + + if (targetUniform->dirty) + { + GLfloat *f = (GLfloat*)targetUniform->data; + GLint *i = (GLint*)targetUniform->data; + + switch (targetUniform->type) + { + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + 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 + if (mDxUniformsDirty) + { + mDevice->SetVertexShaderConstantF(0, (float*)&mVertexConstants, sizeof(dx_VertexConstants) / sizeof(float[4])); + mDevice->SetPixelShaderConstantF(0, (float*)&mPixelConstants, sizeof(dx_PixelConstants) / sizeof(float[4])); + mDxUniformsDirty = false; + } +} + +void Renderer9::applyUniformnfv(gl::LinkedUniform *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(gl::LinkedUniform *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(gl::LinkedUniform *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); +} + +void Renderer9::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) +{ + if (clearParams.colorClearType != GL_FLOAT) + { + // Clearing buffers with non-float values is not supported by Renderer9 and ES 2.0 + UNREACHABLE(); + return; + } + + 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; + } + } + + float depth = gl::clamp01(clearParams.depthClearValue); + DWORD stencil = clearParams.stencilClearValue & 0x000000FF; + + unsigned int stencilUnmasked = 0x0; + if (clearParams.clearStencil && frameBuffer->hasStencil()) + { + unsigned int stencilSize = gl::GetStencilBits(frameBuffer->getStencilbuffer()->getActualFormat()); + stencilUnmasked = (0x1 << stencilSize) - 1; + } + + const bool needMaskedStencilClear = clearParams.clearStencil && + (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; + + bool needMaskedColorClear = false; + D3DCOLOR color = D3DCOLOR_ARGB(255, 0, 0, 0); + if (clearColor) + { + gl::FramebufferAttachment *attachment = frameBuffer->getFirstColorbuffer(); + GLenum internalFormat = attachment->getInternalFormat(); + GLenum actualFormat = attachment->getActualFormat(); + + GLuint internalRedBits = gl::GetRedBits(internalFormat); + GLuint internalGreenBits = gl::GetGreenBits(internalFormat); + GLuint internalBlueBits = gl::GetBlueBits(internalFormat); + GLuint internalAlphaBits = gl::GetAlphaBits(internalFormat); + + GLuint actualRedBits = gl::GetRedBits(actualFormat); + GLuint actualGreenBits = gl::GetGreenBits(actualFormat); + GLuint actualBlueBits = gl::GetBlueBits(actualFormat); + GLuint actualAlphaBits = gl::GetAlphaBits(actualFormat); + + color = D3DCOLOR_ARGB(gl::unorm<8>((internalAlphaBits == 0 && actualAlphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha), + gl::unorm<8>((internalRedBits == 0 && actualRedBits > 0) ? 0.0f : clearParams.colorFClearValue.red), + gl::unorm<8>((internalGreenBits == 0 && actualGreenBits > 0) ? 0.0f : clearParams.colorFClearValue.green), + gl::unorm<8>((internalBlueBits == 0 && actualBlueBits > 0) ? 0.0f : clearParams.colorFClearValue.blue)); + + if ((internalRedBits > 0 && !clearParams.colorMaskRed) || + (internalGreenBits > 0 && !clearParams.colorMaskGreen) || + (internalBlueBits > 0 && !clearParams.colorMaskBlue) || + (internalAlphaBits > 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); + } + + float quad[4][4]; // A quadrilateral covering the target, aligned to match the edges + quad[0][0] = -0.5f; + quad[0][1] = mRenderTargetDesc.height - 0.5f; + quad[0][2] = 0.0f; + quad[0][3] = 1.0f; + + quad[1][0] = mRenderTargetDesc.width - 0.5f; + quad[1][1] = mRenderTargetDesc.height - 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] = mRenderTargetDesc.width - 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); + } +} + +void Renderer9::markAllStateDirty() +{ + mAppliedRenderTargetSerial = 0; + mAppliedDepthbufferSerial = 0; + mAppliedStencilbufferSerial = 0; + mDepthStencilInitialized = false; + mRenderTargetDescInitialized = false; + + mForceSetDepthStencilState = true; + mForceSetRasterState = true; + mForceSetScissor = true; + mForceSetViewport = true; + mForceSetBlendState = true; + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; i++) + { + mForceSetVertexSamplerStates[i] = true; + mCurVertexTextureSerials[i] = 0; + } + for (unsigned int i = 0; i < gl::MAX_TEXTURE_IMAGE_UNITS; i++) + { + mForceSetPixelSamplerStates[i] = true; + mCurPixelTextureSerials[i] = 0; + } + + mAppliedIBSerial = 0; + mAppliedVertexShader = NULL; + mAppliedPixelShader = NULL; + mAppliedProgramSerial = 0; + mDxUniformsDirty = true; + + 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); + + for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) + { + SafeDelete(mNullColorbufferCache[i].buffer); + } +} + +void Renderer9::notifyDeviceLost() +{ + mDeviceLost = true; + mDisplay->notifyDeviceLost(); +} + +bool Renderer9::isDeviceLost() +{ + return mDeviceLost; +} + +// set notify to true to broadcast a message to all contexts of the device loss +bool Renderer9::testDeviceLost(bool notify) +{ + HRESULT status = getDeviceStatusCode(); + bool isLost = FAILED(status); + + if (isLost) + { + // ensure we note the device loss -- + // we'll probably get this done again by notifyDeviceLost + // but best to remember it! + // Note that we don't want to clear the device loss status here + // -- this needs to be done by resetDevice + mDeviceLost = true; + if (notify) + { + notifyDeviceLost(); + } + } + + return isLost; +} + +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(false); + 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(false); + } + 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(false); + } + } + + 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(); + } + + mDeviceLost = false; + + return true; +} + +bool Renderer9::isRemovedDeviceResettable() const +{ + bool success = false; + +#ifdef ANGLE_ENABLE_D3D9EX + 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() == EGL_SUCCESS); +} + +DWORD Renderer9::getAdapterVendor() const +{ + return 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(); +} + +GUID Renderer9::getAdapterIdentifier() const +{ + return mAdapterIdentifier.DeviceIdentifier; +} + +Renderer9::MultisampleSupportInfo Renderer9::getMultiSampleSupport(D3DFORMAT format) +{ + MultisampleSupportInfo support = { 0 }; + + for (unsigned int multiSampleIndex = 0; multiSampleIndex < ArraySize(support.supportedSamples); multiSampleIndex++) + { + HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format, TRUE, + (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL); + + if (SUCCEEDED(result)) + { + support.supportedSamples[multiSampleIndex] = true; + if (multiSampleIndex != D3DMULTISAMPLE_NONMASKABLE) + { + support.maxSupportedSamples = std::max(support.maxSupportedSamples, multiSampleIndex); + } + } + else + { + support.supportedSamples[multiSampleIndex] = false; + } + } + + return support; +} + +unsigned int Renderer9::getMaxVertexTextureImageUnits() const +{ + META_ASSERT(MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 <= gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS); + return mVertexTextureSupport ? MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 : 0; +} + +unsigned int Renderer9::getMaxCombinedTextureImageUnits() const +{ + return gl::MAX_TEXTURE_IMAGE_UNITS + getMaxVertexTextureImageUnits(); +} + +unsigned int Renderer9::getReservedVertexUniformVectors() const +{ + return 2; // dx_ViewAdjust and dx_DepthRange. +} + +unsigned int Renderer9::getReservedFragmentUniformVectors() const +{ + return 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange. +} + +unsigned int Renderer9::getMaxVertexUniformVectors() const +{ + return MAX_VERTEX_CONSTANT_VECTORS_D3D9 - getReservedVertexUniformVectors(); +} + +unsigned int Renderer9::getMaxFragmentUniformVectors() const +{ + const int maxPixelConstantVectors = (getMajorShaderModel() >= 3) ? MAX_PIXEL_CONSTANT_VECTORS_SM3 : MAX_PIXEL_CONSTANT_VECTORS_SM2; + + return maxPixelConstantVectors - getReservedFragmentUniformVectors(); +} + +unsigned int Renderer9::getMaxVaryingVectors() const +{ + return (getMajorShaderModel() >= 3) ? MAX_VARYING_VECTORS_SM3 : MAX_VARYING_VECTORS_SM2; +} + +unsigned int Renderer9::getMaxVertexShaderUniformBuffers() const +{ + return 0; +} + +unsigned int Renderer9::getMaxFragmentShaderUniformBuffers() const +{ + return 0; +} + +unsigned int Renderer9::getReservedVertexUniformBuffers() const +{ + return 0; +} + +unsigned int Renderer9::getReservedFragmentUniformBuffers() const +{ + return 0; +} + +unsigned int Renderer9::getMaxTransformFeedbackBuffers() const +{ + return 0; +} + +unsigned int Renderer9::getMaxTransformFeedbackSeparateComponents() const +{ + return 0; +} + +unsigned int Renderer9::getMaxTransformFeedbackInterleavedComponents() const +{ + return 0; +} + +unsigned int Renderer9::getMaxUniformBufferSize() const +{ + return 0; +} + +bool Renderer9::getShareHandleSupport() const +{ + // PIX doesn't seem to support using share handles, so disable them. + return (mD3d9Ex != NULL) && !gl::perfActive(); +} + +bool Renderer9::getPostSubBufferSupport() const +{ + return true; +} + +int Renderer9::getMaxRecommendedElementsIndices() const +{ + // ES3 only + UNREACHABLE(); + return 0; +} + +int Renderer9::getMaxRecommendedElementsVertices() const +{ + // ES3 only + UNREACHABLE(); + return 0; +} + +bool Renderer9::getSRGBTextureSupport() const +{ + return false; +} + +int Renderer9::getMajorShaderModel() const +{ + return D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion); +} + +DWORD Renderer9::getCapsDeclTypes() const +{ + return mDeviceCaps.DeclTypes; +} + +int Renderer9::getMinSwapInterval() const +{ + return mMinSwapInterval; +} + +int Renderer9::getMaxSwapInterval() const +{ + return mMaxSwapInterval; +} + +int Renderer9::getMaxSupportedSamples() const +{ + return mMaxSupportedSamples; +} + +GLsizei Renderer9::getMaxSupportedFormatSamples(GLenum internalFormat) const +{ + D3DFORMAT format = gl_d3d9::GetTextureFormat(internalFormat); + MultisampleSupportMap::const_iterator itr = mMultiSampleSupport.find(format); + return (itr != mMultiSampleSupport.end()) ? mMaxSupportedSamples : 0; +} + +GLsizei Renderer9::getNumSampleCounts(GLenum internalFormat) const +{ + D3DFORMAT format = gl_d3d9::GetTextureFormat(internalFormat); + MultisampleSupportMap::const_iterator iter = mMultiSampleSupport.find(format); + + unsigned int numCounts = 0; + if (iter != mMultiSampleSupport.end()) + { + const MultisampleSupportInfo& info = iter->second; + for (int i = 0; i < D3DMULTISAMPLE_16_SAMPLES; i++) + { + if (i != D3DMULTISAMPLE_NONMASKABLE && info.supportedSamples[i]) + { + numCounts++; + } + } + } + + return numCounts; +} + +void Renderer9::getSampleCounts(GLenum internalFormat, GLsizei bufSize, GLint *params) const +{ + D3DFORMAT format = gl_d3d9::GetTextureFormat(internalFormat); + MultisampleSupportMap::const_iterator iter = mMultiSampleSupport.find(format); + + if (iter != mMultiSampleSupport.end()) + { + const MultisampleSupportInfo& info = iter->second; + int bufPos = 0; + for (int i = D3DMULTISAMPLE_16_SAMPLES; i >= 0 && bufPos < bufSize; i--) + { + if (i != D3DMULTISAMPLE_NONMASKABLE && info.supportedSamples[i]) + { + params[bufPos++] = i; + } + } + } +} + +int Renderer9::getNearestSupportedSamples(D3DFORMAT format, int requested) const +{ + if (requested == 0) + { + return requested; + } + + MultisampleSupportMap::const_iterator itr = mMultiSampleSupport.find(format); + if (itr == mMultiSampleSupport.end()) + { + if (format == D3DFMT_UNKNOWN) + return 0; + return -1; + } + + for (unsigned int i = requested; i < ArraySize(itr->second.supportedSamples); ++i) + { + if (itr->second.supportedSamples[i] && i != D3DMULTISAMPLE_NONMASKABLE) + { + return i; + } + } + + return -1; +} + +bool Renderer9::copyToRenderTarget(TextureStorageInterface2D *dest, TextureStorageInterface2D *source) +{ + bool result = false; + + if (source && dest) + { + TextureStorage9_2D *source9 = TextureStorage9_2D::makeTextureStorage9_2D(source->getStorageInstance()); + TextureStorage9_2D *dest9 = TextureStorage9_2D::makeTextureStorage9_2D(dest->getStorageInstance()); + + int levels = source9->getLevelCount(); + for (int i = 0; i < levels; ++i) + { + IDirect3DSurface9 *srcSurf = source9->getSurfaceLevel(i, false); + IDirect3DSurface9 *dstSurf = dest9->getSurfaceLevel(i, false); + + result = copyToRenderTarget(dstSurf, srcSurf, source9->isManaged()); + + SafeRelease(srcSurf); + SafeRelease(dstSurf); + + if (!result) + { + return false; + } + } + } + + return result; +} + +bool Renderer9::copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureStorageInterfaceCube *source) +{ + bool result = false; + + if (source && dest) + { + TextureStorage9_Cube *source9 = TextureStorage9_Cube::makeTextureStorage9_Cube(source->getStorageInstance()); + TextureStorage9_Cube *dest9 = TextureStorage9_Cube::makeTextureStorage9_Cube(dest->getStorageInstance()); + int levels = source9->getLevelCount(); + for (int f = 0; f < 6; f++) + { + for (int i = 0; i < levels; i++) + { + IDirect3DSurface9 *srcSurf = source9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false); + IDirect3DSurface9 *dstSurf = dest9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true); + + result = copyToRenderTarget(dstSurf, srcSurf, source9->isManaged()); + + SafeRelease(srcSurf); + SafeRelease(dstSurf); + + if (!result) + { + return false; + } + } + } + } + + return result; +} + +bool Renderer9::copyToRenderTarget(TextureStorageInterface3D *dest, TextureStorageInterface3D *source) +{ + // 3D textures are not available in the D3D9 backend. + UNREACHABLE(); + return false; +} + +bool Renderer9::copyToRenderTarget(TextureStorageInterface2DArray *dest, TextureStorageInterface2DArray *source) +{ + // 2D array textures are not supported by the D3D9 backend. + UNREACHABLE(); + return false; +} + +D3DPOOL Renderer9::getBufferPool(DWORD usage) const +{ + if (mD3d9Ex != NULL) + { + return D3DPOOL_DEFAULT; + } + else + { + if (!(usage & D3DUSAGE_DYNAMIC)) + { + return D3DPOOL_MANAGED; + } + } + + return D3DPOOL_DEFAULT; +} + +bool Renderer9::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorageInterface2D *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->copy(framebuffer, rect, destFormat, xoffset, yoffset, storage, level); +} + +bool Renderer9::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *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->copy(framebuffer, rect, destFormat, xoffset, yoffset, storage, target, level); +} + +bool Renderer9::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface3D *storage, GLint level) +{ + // 3D textures are not available in the D3D9 backend. + UNREACHABLE(); + return false; +} + +bool Renderer9::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface2DArray *storage, GLint level) +{ + // 2D array textures are not available in the D3D9 backend. + UNREACHABLE(); + return false; +} + +bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle &readRect, gl::Framebuffer *drawFramebuffer, const gl::Rectangle &drawRect, + const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter) +{ + ASSERT(filter == GL_NEAREST); + + endScene(); + + if (blitRenderTarget) + { + gl::FramebufferAttachment *readBuffer = readFramebuffer->getColorbuffer(0); + gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getColorbuffer(0); + RenderTarget9 *readRenderTarget = NULL; + RenderTarget9 *drawRenderTarget = NULL; + IDirect3DSurface9* readSurface = NULL; + IDirect3DSurface9* drawSurface = NULL; + + if (readBuffer) + { + readRenderTarget = RenderTarget9::makeRenderTarget9(readBuffer->getRenderTarget()); + } + if (drawBuffer) + { + drawRenderTarget = RenderTarget9::makeRenderTarget9(drawBuffer->getRenderTarget()); + } + + if (readRenderTarget) + { + readSurface = readRenderTarget->getSurface(); + } + if (drawRenderTarget) + { + drawSurface = drawRenderTarget->getSurface(); + } + + if (!readSurface || !drawSurface) + { + ERR("Failed to retrieve the render target."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + gl::Extents srcSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); + gl::Extents dstSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); + + RECT srcRect; + srcRect.left = readRect.x; + srcRect.right = readRect.x + readRect.width; + srcRect.top = readRect.y; + srcRect.bottom = readRect.y + readRect.height; + + RECT dstRect; + dstRect.left = drawRect.x; + dstRect.right = drawRect.x + drawRect.width; + dstRect.top = drawRect.y; + dstRect.bottom = drawRect.y + drawRect.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 = mDevice->StretchRect(readSurface, &srcRect, drawSurface, &dstRect, D3DTEXF_NONE); + + SafeRelease(readSurface); + SafeRelease(drawSurface); + + if (FAILED(result)) + { + ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result); + return false; + } + } + + if (blitDepth || blitStencil) + { + gl::FramebufferAttachment *readBuffer = readFramebuffer->getDepthOrStencilbuffer(); + gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getDepthOrStencilbuffer(); + RenderTarget9 *readDepthStencil = NULL; + RenderTarget9 *drawDepthStencil = NULL; + IDirect3DSurface9* readSurface = NULL; + IDirect3DSurface9* drawSurface = NULL; + + if (readBuffer) + { + readDepthStencil = RenderTarget9::makeRenderTarget9(readBuffer->getDepthStencil()); + } + if (drawBuffer) + { + drawDepthStencil = RenderTarget9::makeRenderTarget9(drawBuffer->getDepthStencil()); + } + + if (readDepthStencil) + { + readSurface = readDepthStencil->getSurface(); + } + if (drawDepthStencil) + { + drawSurface = drawDepthStencil->getSurface(); + } + + if (!readSurface || !drawSurface) + { + ERR("Failed to retrieve the render target."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + HRESULT result = mDevice->StretchRect(readSurface, NULL, drawSurface, NULL, D3DTEXF_NONE); + + SafeRelease(readSurface); + SafeRelease(drawSurface); + + if (FAILED(result)) + { + ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result); + return false; + } + } + + return true; +} + +void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, void* pixels) +{ + ASSERT(pack.pixelBuffer.get() == NULL); + + RenderTarget9 *renderTarget = NULL; + IDirect3DSurface9 *surface = NULL; + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); + + if (colorbuffer) + { + renderTarget = RenderTarget9::makeRenderTarget9(colorbuffer->getRenderTarget()); + } + + if (renderTarget) + { + surface = renderTarget->getSurface(); + } + + if (!surface) + { + // context must be lost + return; + } + + 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); + } + + HRESULT result; + IDirect3DSurface9 *systemSurface = NULL; + bool directToPixels = !pack.reverseRowOrder && pack.alignment <= 4 && getShareHandleSupport() && + x == 0 && y == 0 && UINT(width) == desc.Width && UINT(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 = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &systemSurface, &pixels); + if (FAILED(result)) + { + // Try again without the shared handle + directToPixels = false; + } + } + + if (!directToPixels) + { + result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &systemSurface, NULL); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + SafeRelease(surface); + return gl::error(GL_OUT_OF_MEMORY); + } + } + + result = mDevice->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)) + { + notifyDeviceLost(); + return gl::error(GL_OUT_OF_MEMORY); + } + else + { + UNREACHABLE(); + return; + } + + } + + if (directToPixels) + { + SafeRelease(systemSurface); + return; + } + + RECT rect; + rect.left = gl::clamp(x, 0L, static_cast<LONG>(desc.Width)); + rect.top = gl::clamp(y, 0L, static_cast<LONG>(desc.Height)); + rect.right = gl::clamp(x + width, 0L, static_cast<LONG>(desc.Width)); + rect.bottom = gl::clamp(y + height, 0L, static_cast<LONG>(desc.Height)); + + D3DLOCKED_RECT lock; + result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY); + + if (FAILED(result)) + { + UNREACHABLE(); + SafeRelease(systemSurface); + + return; // No sensible error to generate + } + + unsigned char *source; + int inputPitch; + if (pack.reverseRowOrder) + { + source = ((unsigned char*)lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1); + inputPitch = -lock.Pitch; + } + else + { + source = (unsigned char*)lock.pBits; + inputPitch = lock.Pitch; + } + + GLenum sourceInternalFormat = d3d9_gl::GetInternalFormat(desc.Format); + GLenum sourceFormat = gl::GetFormat(sourceInternalFormat); + GLenum sourceType = gl::GetType(sourceInternalFormat); + + GLuint sourcePixelSize = gl::GetPixelBytes(sourceInternalFormat); + + if (sourceFormat == format && sourceType == type) + { + // Direct copy possible + unsigned char *dest = static_cast<unsigned char*>(pixels); + for (int y = 0; y < rect.bottom - rect.top; y++) + { + memcpy(dest + y * outputPitch, source + y * inputPitch, (rect.right - rect.left) * sourcePixelSize); + } + } + else + { + GLenum destInternalFormat = gl::GetSizedInternalFormat(format, type); + GLuint destPixelSize = gl::GetPixelBytes(destInternalFormat); + GLuint sourcePixelSize = gl::GetPixelBytes(sourceInternalFormat); + + ColorCopyFunction fastCopyFunc = d3d9::GetFastCopyFunction(desc.Format, format, type); + if (fastCopyFunc) + { + // Fast copy is possible through some special function + for (int y = 0; y < rect.bottom - rect.top; y++) + { + for (int x = 0; x < rect.right - rect.left; x++) + { + void *dest = static_cast<unsigned char*>(pixels) + y * outputPitch + x * destPixelSize; + void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourcePixelSize; + + fastCopyFunc(src, dest); + } + } + } + else + { + ColorReadFunction readFunc = d3d9::GetColorReadFunction(desc.Format); + ColorWriteFunction writeFunc = gl::GetColorWriteFunction(format, type); + + gl::ColorF temp; + + for (int y = 0; y < rect.bottom - rect.top; y++) + { + for (int x = 0; x < rect.right - rect.left; x++) + { + void *dest = reinterpret_cast<unsigned char*>(pixels) + y * outputPitch + x * destPixelSize; + void *src = source + y * inputPitch + x * sourcePixelSize; + + // readFunc and writeFunc will be using the same type of color, CopyTexImage + // will not allow the copy otherwise. + readFunc(src, &temp); + writeFunc(&temp, dest); + } + } + } + } + + systemSurface->UnlockRect(); + SafeRelease(systemSurface); +} + +RenderTarget *Renderer9::createRenderTarget(SwapChain *swapChain, bool depth) +{ + SwapChain9 *swapChain9 = SwapChain9::makeSwapChain9(swapChain); + IDirect3DSurface9 *surface = NULL; + if (depth) + { + surface = swapChain9->getDepthStencil(); + } + else + { + surface = swapChain9->getRenderTarget(); + } + + RenderTarget9 *renderTarget = new RenderTarget9(this, surface); + + return renderTarget; +} + +RenderTarget *Renderer9::createRenderTarget(int width, int height, GLenum format, GLsizei samples) +{ + RenderTarget9 *renderTarget = new RenderTarget9(this, width, height, format, samples); + return renderTarget; +} + +ShaderExecutable *Renderer9::loadExecutable(const void *function, size_t length, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers) +{ + // Transform feedback is not supported in ES2 or D3D9 + ASSERT(transformFeedbackVaryings.size() == 0); + + ShaderExecutable9 *executable = NULL; + + switch (type) + { + case rx::SHADER_VERTEX: + { + IDirect3DVertexShader9 *vshader = createVertexShader((DWORD*)function, length); + if (vshader) + { + executable = new ShaderExecutable9(function, length, vshader); + } + } + break; + case rx::SHADER_PIXEL: + { + IDirect3DPixelShader9 *pshader = createPixelShader((DWORD*)function, length); + if (pshader) + { + executable = new ShaderExecutable9(function, length, pshader); + } + } + break; + default: + UNREACHABLE(); + break; + } + + return executable; +} + +ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround) +{ + // Transform feedback is not supported in ES2 or D3D9 + ASSERT(transformFeedbackVaryings.size() == 0); + + const char *profile = NULL; + + switch (type) + { + case rx::SHADER_VERTEX: + profile = getMajorShaderModel() >= 3 ? "vs_3_0" : "vs_2_0"; + break; + case rx::SHADER_PIXEL: + profile = getMajorShaderModel() >= 3 ? "ps_3_0" : "ps_2_0"; + break; + default: + UNREACHABLE(); + return NULL; + } + + UINT flags = ANGLE_COMPILE_OPTIMIZATION_LEVEL; + + if (workaround == ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION) + { + flags = D3DCOMPILE_SKIP_OPTIMIZATION; + } + else if (workaround == ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION) + { + flags = D3DCOMPILE_OPTIMIZATION_LEVEL3; + } + else ASSERT(workaround == ANGLE_D3D_WORKAROUND_NONE); + + if (gl::perfActive()) + { +#ifndef NDEBUG + flags = D3DCOMPILE_SKIP_OPTIMIZATION; +#endif + + flags |= D3DCOMPILE_DEBUG; + + std::string sourcePath = getTempPath(); + std::string sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(shaderHLSL); + writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size()); + } + + // 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. + const UINT extraFlags[] = + { + flags, + flags | D3DCOMPILE_AVOID_FLOW_CONTROL, + flags | D3DCOMPILE_PREFER_FLOW_CONTROL + }; + + const static char *extraFlagNames[] = + { + "default", + "avoid flow control", + "prefer flow control" + }; + + int attempts = ArraySize(extraFlags); + + ID3DBlob *binary = (ID3DBlob*)mCompiler.compileToBinary(infoLog, shaderHLSL, profile, extraFlags, extraFlagNames, attempts); + if (!binary) + { + return NULL; + } + + ShaderExecutable *executable = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, + transformFeedbackVaryings, separatedOutputBuffers); + SafeRelease(binary); + + return executable; +} + +rx::UniformStorage *Renderer9::createUniformStorage(size_t storageSize) +{ + return new UniformStorage(storageSize); +} + +bool Renderer9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) +{ + return mBlit->boxFilter(source, dest); +} + +D3DPOOL Renderer9::getTexturePool(DWORD usage) const +{ + if (mD3d9Ex != NULL) + { + return D3DPOOL_DEFAULT; + } + else + { + if (!(usage & (D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET))) + { + return D3DPOOL_MANAGED; + } + } + + return D3DPOOL_DEFAULT; +} + +bool Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged) +{ + if (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 false; + } + } + + return true; +} + +Image *Renderer9::createImage() +{ + return new Image9(); +} + +void Renderer9::generateMipmap(Image *dest, Image *src) +{ + Image9 *src9 = Image9::makeImage9(src); + Image9 *dst9 = Image9::makeImage9(dest); + Image9::generateMipmap(dst9, src9); +} + +TextureStorage *Renderer9::createTextureStorage2D(SwapChain *swapChain) +{ + SwapChain9 *swapChain9 = SwapChain9::makeSwapChain9(swapChain); + return new TextureStorage9_2D(this, swapChain9); +} + +TextureStorage *Renderer9::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) +{ + return new TextureStorage9_2D(this, internalformat, renderTarget, width, height, levels); +} + +TextureStorage *Renderer9::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels) +{ + return new TextureStorage9_Cube(this, internalformat, renderTarget, size, levels); +} + +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; +} + +Texture2DImpl *Renderer9::createTexture2D() +{ + return new TextureD3D_2D(this); +} + +TextureCubeImpl *Renderer9::createTextureCube() +{ + return new TextureD3D_Cube(this); +} + +Texture3DImpl *Renderer9::createTexture3D() +{ + return new TextureD3D_3D(this); +} + +Texture2DArrayImpl *Renderer9::createTexture2DArray() +{ + return new TextureD3D_2DArray(this); +} + +bool Renderer9::getLUID(LUID *adapterLuid) const +{ + adapterLuid->HighPart = 0; + adapterLuid->LowPart = 0; + + if (mD3d9Ex) + { + mD3d9Ex->GetAdapterLUID(mAdapter, adapterLuid); + return true; + } + + return false; +} + +GLenum Renderer9::getNativeTextureFormat(GLenum internalFormat) const +{ + return d3d9_gl::GetInternalFormat(gl_d3d9::GetTextureFormat(internalFormat)); +} + +rx::VertexConversionType Renderer9::getVertexConversionType(const gl::VertexFormat &vertexFormat) const +{ + return d3d9::GetVertexConversionType(vertexFormat); +} + +GLenum Renderer9::getVertexComponentType(const gl::VertexFormat &vertexFormat) const +{ + D3DDECLTYPE declType = d3d9::GetNativeVertexFormat(vertexFormat); + return d3d9::GetDeclTypeComponentType(declType); +} + +void Renderer9::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const +{ + d3d9_gl::GenerateCaps(mD3d9, mDevice, mDeviceType, mAdapter, outCaps, outTextureCaps, outExtensions); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h new file mode 100644 index 0000000000..070623c9db --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h @@ -0,0 +1,364 @@ +// +// 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 LIBGLESV2_RENDERER_RENDERER9_H_ +#define LIBGLESV2_RENDERER_RENDERER9_H_ + +#include "common/angleutils.h" +#include "common/mathutil.h" +#include "libGLESv2/renderer/d3d/HLSLCompiler.h" +#include "libGLESv2/renderer/d3d/d3d9/ShaderCache.h" +#include "libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h" +#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/renderer/RenderTarget.h" + +namespace gl +{ +class FramebufferAttachment; +} + +namespace rx +{ +class VertexDataManager; +class IndexDataManager; +class StreamingIndexBufferInterface; +struct TranslatedAttribute; +class Blit9; + +class Renderer9 : public Renderer +{ + public: + Renderer9(egl::Display *display, EGLNativeDisplayType hDc, EGLint requestedDisplay); + virtual ~Renderer9(); + + static Renderer9 *makeRenderer9(Renderer *renderer); + + virtual EGLint initialize(); + virtual bool resetDevice(); + + virtual int generateConfigs(ConfigDesc **configDescList); + virtual void deleteConfigs(ConfigDesc *configDescList); + + void startScene(); + void endScene(); + + virtual void sync(bool block); + + virtual SwapChain *createSwapChain(HWND window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); + + IDirect3DQuery9* allocateEventQuery(); + void freeEventQuery(IDirect3DQuery9* query); + + // resource creation + IDirect3DVertexShader9 *createVertexShader(const DWORD *function, size_t length); + IDirect3DPixelShader9 *createPixelShader(const DWORD *function, size_t length); + HRESULT createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer); + HRESULT createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer); + virtual void generateSwizzle(gl::Texture *texture); + virtual void setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler); + virtual void setTexture(gl::SamplerType type, int index, gl::Texture *texture); + + virtual bool setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]); + + virtual void setRasterizerState(const gl::RasterizerState &rasterState); + virtual void setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask); + virtual void setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, + int stencilBackRef, bool frontFaceCCW); + + virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled); + virtual bool setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, + bool ignoreViewport); + + virtual bool applyRenderTarget(gl::Framebuffer *frameBuffer); + virtual void applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive); + virtual void applyUniforms(const gl::ProgramBinary &programBinary); + virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount); + virtual GLenum applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], + GLint first, GLsizei count, GLsizei instances); + virtual GLenum applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); + + virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]); + + virtual void drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive); + virtual void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); + + virtual void clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer); + + virtual void markAllStateDirty(); + + // lost device + void notifyDeviceLost(); + virtual bool isDeviceLost(); + virtual bool testDeviceLost(bool notify); + virtual bool testDeviceResettable(); + + IDirect3DDevice9 *getDevice() { return mDevice; } + virtual DWORD getAdapterVendor() const; + virtual std::string getRendererDescription() const; + virtual GUID getAdapterIdentifier() const; + + virtual unsigned int getMaxVertexTextureImageUnits() const; + virtual unsigned int getMaxCombinedTextureImageUnits() const; + virtual unsigned int getReservedVertexUniformVectors() const; + virtual unsigned int getReservedFragmentUniformVectors() const; + virtual unsigned int getMaxVertexUniformVectors() const; + virtual unsigned int getMaxFragmentUniformVectors() const; + virtual unsigned int getMaxVaryingVectors() const; + virtual unsigned int getMaxVertexShaderUniformBuffers() const; + virtual unsigned int getMaxFragmentShaderUniformBuffers() const; + virtual unsigned int getReservedVertexUniformBuffers() const; + virtual unsigned int getReservedFragmentUniformBuffers() const; + virtual unsigned int getMaxTransformFeedbackBuffers() const; + virtual unsigned int getMaxTransformFeedbackSeparateComponents() const; + virtual unsigned int getMaxTransformFeedbackInterleavedComponents() const; + virtual unsigned int getMaxUniformBufferSize() const; + virtual bool getShareHandleSupport() const; + virtual bool getPostSubBufferSupport() const; + virtual int getMaxRecommendedElementsIndices() const; + virtual int getMaxRecommendedElementsVertices() const; + virtual bool getSRGBTextureSupport() const; + + virtual int getMajorShaderModel() const; + DWORD getCapsDeclTypes() const; + virtual int getMinSwapInterval() const; + virtual int getMaxSwapInterval() const; + + virtual GLsizei getMaxSupportedSamples() const; + virtual GLsizei getMaxSupportedFormatSamples(GLenum internalFormat) const; + virtual GLsizei getNumSampleCounts(GLenum internalFormat) const; + virtual void getSampleCounts(GLenum internalFormat, GLsizei bufSize, GLint *params) const; + int getNearestSupportedSamples(D3DFORMAT format, int requested) const; + + // Pixel operations + virtual bool copyToRenderTarget(TextureStorageInterface2D *dest, TextureStorageInterface2D *source); + virtual bool copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureStorageInterfaceCube *source); + virtual bool copyToRenderTarget(TextureStorageInterface3D *dest, TextureStorageInterface3D *source); + virtual bool copyToRenderTarget(TextureStorageInterface2DArray *dest, TextureStorageInterface2DArray *source); + + virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level); + virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level); + virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface3D *storage, GLint level); + virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface2DArray *storage, GLint level); + + virtual bool blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, + const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter); + virtual void readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, void* pixels); + + // RenderTarget creation + virtual RenderTarget *createRenderTarget(SwapChain *swapChain, bool depth); + virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples); + + // Shader operations + virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers); + virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround); + virtual UniformStorage *createUniformStorage(size_t storageSize); + + // Image operations + virtual Image *createImage(); + virtual void generateMipmap(Image *dest, Image *source); + virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain); + virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); + virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels); + virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); + + // Texture creation + virtual Texture2DImpl *createTexture2D(); + virtual TextureCubeImpl *createTextureCube(); + virtual Texture3DImpl *createTexture3D(); + virtual Texture2DArrayImpl *createTexture2DArray(); + + // Buffer creation + virtual BufferImpl *createBuffer(); + virtual VertexBuffer *createVertexBuffer(); + virtual IndexBuffer *createIndexBuffer(); + + // Vertex Array creation + virtual VertexArrayImpl *createVertexArray(); + + // Query and Fence creation + virtual QueryImpl *createQuery(GLenum type); + virtual FenceImpl *createFence(); + + // Buffer-to-texture and Texture-to-buffer copies + virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const; + virtual bool fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + + // D3D9-renderer specific methods + bool boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); + + D3DPOOL getTexturePool(DWORD usage) const; + + virtual bool getLUID(LUID *adapterLuid) const; + virtual GLenum getNativeTextureFormat(GLenum internalFormat) const; + virtual rx::VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const; + virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const; + + private: + DISALLOW_COPY_AND_ASSIGN(Renderer9); + + virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const; + + void release(); + + void applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat *v); + void applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v); + void applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v); + + void drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); + void drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); + + bool copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged); + gl::FramebufferAttachment *getNullColorbuffer(gl::FramebufferAttachment *depthbuffer); + + D3DPOOL getBufferPool(DWORD usage) const; + + HMODULE mD3d9Module; + HDC mDc; + + 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; + + bool mDeviceLost; + D3DCAPS9 mDeviceCaps; + D3DADAPTER_IDENTIFIER9 mAdapterIdentifier; + + D3DPRIMITIVETYPE mPrimitiveType; + int mPrimitiveCount; + GLsizei mRepeatDraw; + + bool mSceneStarted; + int mMinSwapInterval; + int mMaxSwapInterval; + + bool mVertexTextureSupport; + + struct MultisampleSupportInfo + { + bool supportedSamples[D3DMULTISAMPLE_16_SAMPLES + 1]; + unsigned int maxSupportedSamples; + }; + typedef std::map<D3DFORMAT, MultisampleSupportInfo> MultisampleSupportMap; + MultisampleSupportMap mMultiSampleSupport; + unsigned int mMaxSupportedSamples; + + MultisampleSupportInfo getMultiSampleSupport(D3DFORMAT format); + + // current render target states + unsigned int mAppliedRenderTargetSerial; + unsigned int mAppliedDepthbufferSerial; + unsigned int mAppliedStencilbufferSerial; + bool mDepthStencilInitialized; + bool mRenderTargetDescInitialized; + rx::RenderTarget::Desc mRenderTargetDesc; + unsigned int mCurStencilSize; + unsigned int mCurDepthSize; + + IDirect3DStateBlock9 *mMaskedClearSavedState; + + // previously set render states + bool mForceSetDepthStencilState; + gl::DepthStencilState mCurDepthStencilState; + int mCurStencilRef; + int mCurStencilBackRef; + bool mCurFrontFaceCCW; + + bool mForceSetRasterState; + gl::RasterizerState mCurRasterState; + + bool mForceSetScissor; + gl::Rectangle mCurScissor; + bool mScissorEnabled; + + bool mForceSetViewport; + gl::Rectangle mCurViewport; + float mCurNear; + float mCurFar; + float mCurDepthFront; + + bool mForceSetBlendState; + gl::BlendState mCurBlendState; + gl::ColorF mCurBlendColor; + GLuint mCurSampleMask; + + // Currently applied sampler states + bool mForceSetVertexSamplerStates[gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + gl::SamplerState mCurVertexSamplerStates[gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + + bool mForceSetPixelSamplerStates[gl::MAX_TEXTURE_IMAGE_UNITS]; + gl::SamplerState mCurPixelSamplerStates[gl::MAX_TEXTURE_IMAGE_UNITS]; + + // Currently applied textures + unsigned int mCurVertexTextureSerials[gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + unsigned int mCurPixelTextureSerials[gl::MAX_TEXTURE_IMAGE_UNITS]; + + unsigned int mAppliedIBSerial; + IDirect3DVertexShader9 *mAppliedVertexShader; + IDirect3DPixelShader9 *mAppliedPixelShader; + unsigned int mAppliedProgramSerial; + + rx::dx_VertexConstants mVertexConstants; + rx::dx_PixelConstants mPixelConstants; + bool mDxUniformsDirty; + + // 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; + + 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; + +}; + +} +#endif // LIBGLESV2_RENDERER_RENDERER9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h new file mode 100644 index 0000000000..a03528c9b5 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h @@ -0,0 +1,102 @@ +// +// 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 LIBGLESV2_RENDERER_SHADER_CACHE_H_ +#define LIBGLESV2_RENDERER_SHADER_CACHE_H_ + +#include "common/debug.h" + +namespace rx +{ +template <typename ShaderObject> +class ShaderCache +{ + public: + ShaderCache() : mDevice(NULL) + { + } + + ~ShaderCache() + { + // Call clear while the device is still valid. + ASSERT(mMap.empty()); + } + + void initialize(IDirect3DDevice9* device) + { + mDevice = device; + } + + ShaderObject *create(const DWORD *function, size_t length) + { + std::string key(reinterpret_cast<const char*>(function), length); + typename Map::iterator it = mMap.find(key); + if (it != mMap.end()) + { + it->second->AddRef(); + return it->second; + } + + ShaderObject *shader; + HRESULT result = createShader(function, &shader); + if (FAILED(result)) + { + return NULL; + } + + // Random eviction policy. + if (mMap.size() >= kMaxMapSize) + { + SafeRelease(mMap.begin()->second); + mMap.erase(mMap.begin()); + } + + shader->AddRef(); + mMap[key] = shader; + + return shader; + } + + void clear() + { + for (typename Map::iterator it = mMap.begin(); it != mMap.end(); ++it) + { + SafeRelease(it->second); + } + + mMap.clear(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ShaderCache); + + 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 // LIBGLESV2_RENDERER_SHADER_CACHE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.cpp new file mode 100644 index 0000000000..c10ddbf6ce --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.cpp @@ -0,0 +1,54 @@ +#include "precompiled.h" +// +// 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 "libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.h" + +#include "common/debug.h" + +namespace rx +{ + +ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirect3DPixelShader9 *executable) + : ShaderExecutable(function, length) +{ + mPixelExecutable = executable; + mVertexExecutable = NULL; +} + +ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable) + : ShaderExecutable(function, length) +{ + mVertexExecutable = executable; + mPixelExecutable = NULL; +} + +ShaderExecutable9::~ShaderExecutable9() +{ + SafeRelease(mVertexExecutable); + SafeRelease(mPixelExecutable); +} + +ShaderExecutable9 *ShaderExecutable9::makeShaderExecutable9(ShaderExecutable *executable) +{ + ASSERT(HAS_DYNAMIC_TYPE(ShaderExecutable9*, executable)); + return static_cast<ShaderExecutable9*>(executable); +} + +IDirect3DVertexShader9 *ShaderExecutable9::getVertexShader() const +{ + return mVertexExecutable; +} + +IDirect3DPixelShader9 *ShaderExecutable9::getPixelShader() const +{ + return mPixelExecutable; +} + +}
\ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.h new file mode 100644 index 0000000000..fa1e6c2844 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.h @@ -0,0 +1,39 @@ +// +// 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 LIBGLESV2_RENDERER_SHADEREXECUTABLE9_H_ +#define LIBGLESV2_RENDERER_SHADEREXECUTABLE9_H_ + +#include "libGLESv2/renderer/ShaderExecutable.h" + +namespace rx +{ + +class ShaderExecutable9 : public ShaderExecutable +{ + public: + ShaderExecutable9(const void *function, size_t length, IDirect3DPixelShader9 *executable); + ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable); + virtual ~ShaderExecutable9(); + + static ShaderExecutable9 *makeShaderExecutable9(ShaderExecutable *executable); + + IDirect3DPixelShader9 *getPixelShader() const; + IDirect3DVertexShader9 *getVertexShader() const; + + private: + DISALLOW_COPY_AND_ASSIGN(ShaderExecutable9); + + IDirect3DPixelShader9 *mPixelExecutable; + IDirect3DVertexShader9 *mVertexExecutable; +}; + +} + +#endif // LIBGLESV2_RENDERER_SHADEREXECUTABLE9_H_
\ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp new file mode 100644 index 0000000000..c6567b635f --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp @@ -0,0 +1,416 @@ +#include "precompiled.h" +// +// 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 "libGLESv2/renderer/d3d/d3d9/SwapChain9.h" +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ + +SwapChain9::SwapChain9(Renderer9 *renderer, HWND window, HANDLE shareHandle, + GLenum backBufferFormat, GLenum depthBufferFormat) + : mRenderer(renderer), SwapChain(window, shareHandle, backBufferFormat, depthBufferFormat) +{ + mSwapChain = NULL; + mBackBuffer = NULL; + mDepthStencil = NULL; + mRenderTarget = NULL; + mOffscreenTexture = NULL; + mWidth = -1; + mHeight = -1; + mSwapInterval = -1; +} + +SwapChain9::~SwapChain9() +{ + release(); +} + +void SwapChain9::release() +{ + SafeRelease(mSwapChain); + SafeRelease(mBackBuffer); + SafeRelease(mDepthStencil); + SafeRelease(mRenderTarget); + SafeRelease(mOffscreenTexture); + + if (mWindow) + { + mShareHandle = NULL; + } +} + +static DWORD convertInterval(EGLint interval) +{ +#if ANGLE_FORCE_VSYNC_OFF + 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); + + HANDLE *pShareHandle = NULL; + if (!mWindow && mRenderer->getShareHandleSupport()) + { + pShareHandle = &mShareHandle; + } + + result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET, + gl_d3d9::GetTextureFormat(mBackBufferFormat), + 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); + } + + if (mWindow) + { + D3DPRESENT_PARAMETERS presentParameters = {0}; + presentParameters.AutoDepthStencilFormat = gl_d3d9::GetRenderFormat(mDepthBufferFormat); + presentParameters.BackBufferCount = 1; + presentParameters.BackBufferFormat = gl_d3d9::GetRenderFormat(mBackBufferFormat); + presentParameters.EnableAutoDepthStencil = FALSE; + presentParameters.Flags = 0; + presentParameters.hDeviceWindow = mWindow; + 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 (mRenderer->getAdapterVendor() == VENDOR_ID_INTEL) + { + 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(mWindow, NULL, FALSE); + } + + if (mDepthBufferFormat != GL_NONE) + { + result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight, + gl_d3d9::GetRenderFormat(mDepthBufferFormat), + 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, EGLint) +{ + 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, mWidth, 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 = + { + x, mHeight - y - height, + x + width, 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 == 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; +} + +SwapChain9 *SwapChain9::makeSwapChain9(SwapChain *swapChain) +{ + ASSERT(HAS_DYNAMIC_TYPE(rx::SwapChain9*, swapChain)); + return static_cast<rx::SwapChain9*>(swapChain); +} + +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/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h new file mode 100644 index 0000000000..4d756f80d1 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h @@ -0,0 +1,55 @@ +// +// 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 LIBGLESV2_RENDERER_SWAPCHAIN9_H_ +#define LIBGLESV2_RENDERER_SWAPCHAIN9_H_ + +#include "common/angleutils.h" +#include "libGLESv2/renderer/SwapChain.h" + +namespace rx +{ +class Renderer9; + +class SwapChain9 : public SwapChain +{ + public: + SwapChain9(Renderer9 *renderer, HWND window, HANDLE shareHandle, + GLenum backBufferFormat, GLenum depthBufferFormat); + 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, EGLint); + virtual void recreate(); + + virtual IDirect3DSurface9 *getRenderTarget(); + virtual IDirect3DSurface9 *getDepthStencil(); + virtual IDirect3DTexture9 *getOffscreenTexture(); + + static SwapChain9 *makeSwapChain9(SwapChain *swapChain); + + private: + DISALLOW_COPY_AND_ASSIGN(SwapChain9); + + void release(); + + Renderer9 *mRenderer; + EGLint mHeight; + EGLint mWidth; + EGLint mSwapInterval; + + IDirect3DSwapChain9 *mSwapChain; + IDirect3DSurface9 *mBackBuffer; + IDirect3DSurface9 *mRenderTarget; + IDirect3DSurface9 *mDepthStencil; + IDirect3DTexture9* mOffscreenTexture; +}; + +} +#endif // LIBGLESV2_RENDERER_SWAPCHAIN9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp new file mode 100644 index 0000000000..b065ee80fe --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp @@ -0,0 +1,307 @@ +#include "precompiled.h" +// +// 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 "libGLESv2/main.h" +#include "libGLESv2/renderer/d3d/TextureD3D.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" +#include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h" +#include "libGLESv2/renderer/d3d/d3d9/SwapChain9.h" +#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/Texture.h" + +namespace rx +{ +TextureStorage9::TextureStorage9(Renderer *renderer, DWORD usage) + : mTopLevel(0), + mRenderer(Renderer9::makeRenderer9(renderer)), + mD3DUsage(usage), + mD3DPool(mRenderer->getTexturePool(usage)) +{ +} + +TextureStorage9::~TextureStorage9() +{ +} + +TextureStorage9 *TextureStorage9::makeTextureStorage9(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9*, storage)); + return static_cast<TextureStorage9*>(storage); +} + +DWORD TextureStorage9::GetTextureUsage(GLenum internalformat, bool renderTarget) +{ + DWORD d3dusage = 0; + + if (gl::GetDepthBits(internalformat) > 0 || + gl::GetStencilBits(internalformat) > 0) + { + d3dusage |= D3DUSAGE_DEPTHSTENCIL; + } + else if (renderTarget && (gl_d3d9::GetRenderFormat(internalformat) != 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); +} + +D3DPOOL TextureStorage9::getPool() const +{ + return mD3DPool; +} + +DWORD TextureStorage9::getUsage() const +{ + return mD3DUsage; +} + +int TextureStorage9::getTopLevel() const +{ + return mTopLevel; +} + +int TextureStorage9::getLevelCount() const +{ + return getBaseTexture() ? (getBaseTexture()->GetLevelCount() - getTopLevel()) : 0; +} + +TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain) + : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET) +{ + IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture(); + mTexture = surfaceTexture; + mRenderTarget = NULL; + + initializeRenderTarget(); +} + +TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) + : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) +{ + mTexture = NULL; + mRenderTarget = NULL; + // 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 (width > 0 && height > 0) + { + IDirect3DDevice9 *device = mRenderer->getDevice(); + D3DFORMAT format = gl_d3d9::GetTextureFormat(internalformat); + d3d9::MakeValidSize(false, format, &width, &height, &mTopLevel); + UINT creationLevels = (levels == 0) ? 0 : mTopLevel + levels; + + HRESULT result = device->CreateTexture(width, height, creationLevels, getUsage(), format, getPool(), &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + gl::error(GL_OUT_OF_MEMORY); + } + } + + initializeRenderTarget(); +} + +TextureStorage9_2D::~TextureStorage9_2D() +{ + SafeRelease(mTexture); + SafeDelete(mRenderTarget); +} + +TextureStorage9_2D *TextureStorage9_2D::makeTextureStorage9_2D(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_2D*, storage)); + return static_cast<TextureStorage9_2D*>(storage); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *TextureStorage9_2D::getSurfaceLevel(int level, bool dirty) +{ + IDirect3DSurface9 *surface = NULL; + + if (mTexture) + { + HRESULT result = mTexture->GetSurfaceLevel(level + mTopLevel, &surface); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + // With managed textures the driver needs to be informed of updates to the lower mipmap levels + if (level + mTopLevel != 0 && isManaged() && dirty) + { + mTexture->AddDirtyRect(NULL); + } + } + + return surface; +} + +RenderTarget *TextureStorage9_2D::getRenderTarget(int level) +{ + return mRenderTarget; +} + +void TextureStorage9_2D::generateMipmap(int level) +{ + IDirect3DSurface9 *upper = getSurfaceLevel(level - 1, false); + IDirect3DSurface9 *lower = getSurfaceLevel(level, true); + + if (upper != NULL && lower != NULL) + { + mRenderer->boxFilter(upper, lower); + } + + SafeRelease(upper); + SafeRelease(lower); +} + +IDirect3DBaseTexture9 *TextureStorage9_2D::getBaseTexture() const +{ + return mTexture; +} + +void TextureStorage9_2D::initializeRenderTarget() +{ + ASSERT(mRenderTarget == NULL); + + if (mTexture != NULL && isRenderTarget()) + { + IDirect3DSurface9 *surface = getSurfaceLevel(0, false); + + mRenderTarget = new RenderTarget9(mRenderer, surface); + } +} + +TextureStorage9_Cube::TextureStorage9_Cube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels) + : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) +{ + mTexture = NULL; + for (int i = 0; i < 6; ++i) + { + mRenderTarget[i] = NULL; + } + + // 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 (size > 0) + { + IDirect3DDevice9 *device = mRenderer->getDevice(); + int height = size; + D3DFORMAT format = gl_d3d9::GetTextureFormat(internalformat); + d3d9::MakeValidSize(false, format, &size, &height, &mTopLevel); + UINT creationLevels = (levels == 0) ? 0 : mTopLevel + levels; + + HRESULT result = device->CreateCubeTexture(size, creationLevels, getUsage(), format, getPool(), &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + gl::error(GL_OUT_OF_MEMORY); + } + } + + initializeRenderTarget(); +} + +TextureStorage9_Cube::~TextureStorage9_Cube() +{ + SafeRelease(mTexture); + + for (int i = 0; i < 6; ++i) + { + SafeDelete(mRenderTarget[i]); + } +} + +TextureStorage9_Cube *TextureStorage9_Cube::makeTextureStorage9_Cube(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_Cube*, storage)); + return static_cast<TextureStorage9_Cube*>(storage); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *TextureStorage9_Cube::getCubeMapSurface(GLenum faceTarget, int level, bool dirty) +{ + IDirect3DSurface9 *surface = NULL; + + if (mTexture) + { + D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(faceTarget); + HRESULT result = mTexture->GetCubeMapSurface(face, level + mTopLevel, &surface); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + // With managed textures the driver needs to be informed of updates to the lower mipmap levels + if (level != 0 && isManaged() && dirty) + { + mTexture->AddDirtyRect(face, NULL); + } + } + + return surface; +} + +RenderTarget *TextureStorage9_Cube::getRenderTargetFace(GLenum faceTarget, int level) +{ + return mRenderTarget[TextureD3D_Cube::targetToIndex(faceTarget)]; +} + +void TextureStorage9_Cube::generateMipmap(int faceIndex, int level) +{ + IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level - 1, false); + IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level, true); + + if (upper != NULL && lower != NULL) + { + mRenderer->boxFilter(upper, lower); + } + + SafeRelease(upper); + SafeRelease(lower); +} + +IDirect3DBaseTexture9 *TextureStorage9_Cube::getBaseTexture() const +{ + return mTexture; +} + +void TextureStorage9_Cube::initializeRenderTarget() +{ + if (mTexture != NULL && isRenderTarget()) + { + IDirect3DSurface9 *surface = NULL; + + for (int i = 0; i < 6; ++i) + { + ASSERT(mRenderTarget[i] == NULL); + + surface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, false); + + mRenderTarget[i] = new RenderTarget9(mRenderer, surface); + } + } +} + +}
\ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h new file mode 100644 index 0000000000..cc7c155d34 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h @@ -0,0 +1,109 @@ +// +// 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 LIBGLESV2_RENDERER_TEXTURESTORAGE9_H_ +#define LIBGLESV2_RENDERER_TEXTURESTORAGE9_H_ + +#include "libGLESv2/renderer/d3d/TextureStorage.h" +#include "common/debug.h" + +namespace rx +{ +class Renderer9; +class SwapChain9; +class RenderTarget; +class RenderTarget9; + +class TextureStorage9 : public TextureStorage +{ + public: + virtual ~TextureStorage9(); + + static TextureStorage9 *makeTextureStorage9(TextureStorage *storage); + + static DWORD GetTextureUsage(GLenum internalformat, bool renderTarget); + + D3DPOOL getPool() const; + DWORD getUsage() const; + + virtual IDirect3DBaseTexture9 *getBaseTexture() const = 0; + virtual RenderTarget *getRenderTarget(int level) { return NULL; } + virtual RenderTarget *getRenderTargetFace(GLenum faceTarget, int level) { return NULL; } + virtual RenderTarget *getRenderTargetLayer(int mipLevel, int layer) { return NULL; } + virtual void generateMipmap(int level) {}; + virtual void generateMipmap(int face, int level) {}; + + virtual int getTopLevel() const; + virtual bool isRenderTarget() const; + virtual bool isManaged() const; + virtual int getLevelCount() const; + + protected: + int mTopLevel; + Renderer9 *mRenderer; + + TextureStorage9(Renderer *renderer, DWORD usage); + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage9); + + const DWORD mD3DUsage; + const D3DPOOL mD3DPool; +}; + +class TextureStorage9_2D : public TextureStorage9 +{ + public: + TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain); + TextureStorage9_2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); + virtual ~TextureStorage9_2D(); + + static TextureStorage9_2D *makeTextureStorage9_2D(TextureStorage *storage); + + IDirect3DSurface9 *getSurfaceLevel(int level, bool dirty); + virtual RenderTarget *getRenderTarget(int level); + virtual IDirect3DBaseTexture9 *getBaseTexture() const; + virtual void generateMipmap(int level); + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage9_2D); + + void initializeRenderTarget(); + + IDirect3DTexture9 *mTexture; + RenderTarget9 *mRenderTarget; +}; + +class TextureStorage9_Cube : public TextureStorage9 +{ + public: + TextureStorage9_Cube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels); + virtual ~TextureStorage9_Cube(); + + static TextureStorage9_Cube *makeTextureStorage9_Cube(TextureStorage *storage); + + IDirect3DSurface9 *getCubeMapSurface(GLenum faceTarget, int level, bool dirty); + virtual RenderTarget *getRenderTargetFace(GLenum faceTarget, int level); + virtual IDirect3DBaseTexture9 *getBaseTexture() const; + virtual void generateMipmap(int faceIndex, int level); + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage9_Cube); + + void initializeRenderTarget(); + + IDirect3DCubeTexture9 *mTexture; + RenderTarget9 *mRenderTarget[6]; +}; + +} + +#endif // LIBGLESV2_RENDERER_TEXTURESTORAGE9_H_ + diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexArray9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexArray9.h new file mode 100644 index 0000000000..66a6c64d81 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexArray9.h @@ -0,0 +1,43 @@ +// +// 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 LIBGLESV2_RENDERER_VERTEXARRAY9_H_ +#define LIBGLESV2_RENDERER_VERTEXARRAY9_H_ + +#include "libGLESv2/renderer/VertexArrayImpl.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ +class Renderer9; + +class VertexArray9 : public VertexArrayImpl +{ + public: + VertexArray9(rx::Renderer9 *renderer) + : VertexArrayImpl(), + mRenderer(renderer) + { + } + + virtual ~VertexArray9() { } + + virtual void setElementArrayBuffer(const gl::Buffer *buffer) { } + virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) { } + virtual void setAttributeDivisor(size_t idx, GLuint divisor) { } + virtual void enableAttribute(size_t idx, bool enabledState) { } + + private: + DISALLOW_COPY_AND_ASSIGN(VertexArray9); + + rx::Renderer9 *mRenderer; +}; + +} + +#endif // LIBGLESV2_RENDERER_VERTEXARRAY9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp new file mode 100644 index 0000000000..d260640dbe --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp @@ -0,0 +1,252 @@ +#include "precompiled.h" +// +// 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 "libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h" +#include "libGLESv2/renderer/vertexconversion.h" +#include "libGLESv2/renderer/BufferImpl.h" +#include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" + +#include "libGLESv2/Buffer.h" + +namespace rx +{ + +VertexBuffer9::VertexBuffer9(rx::Renderer9 *const renderer) : mRenderer(renderer) +{ + mVertexBuffer = NULL; + mBufferSize = 0; + mDynamicUsage = false; +} + +VertexBuffer9::~VertexBuffer9() +{ + SafeRelease(mVertexBuffer); +} + +bool 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)) + { + ERR("Out of memory allocating a vertex buffer of size %lu.", size); + return false; + } + } + + mBufferSize = size; + mDynamicUsage = dynamicUsage; + return true; +} + +VertexBuffer9 *VertexBuffer9::makeVertexBuffer9(VertexBuffer *vertexBuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer9*, vertexBuffer)); + return static_cast<VertexBuffer9*>(vertexBuffer); +} + +bool VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset) +{ + if (mVertexBuffer) + { + gl::Buffer *buffer = attrib.buffer.get(); + + int inputStride = gl::ComputeVertexAttributeStride(attrib); + int elementSize = gl::ComputeVertexAttributeTypeSize(attrib); + + DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0; + + void *mapPtr = NULL; + + unsigned int mapSize; + if (!spaceRequired(attrib, count, instances, &mapSize)) + { + return false; + } + + HRESULT result = mVertexBuffer->Lock(offset, mapSize, &mapPtr, lockFlags); + + if (FAILED(result)) + { + ERR("Lock failed with error 0x%08x", result); + return false; + } + + const char *input = NULL; + if (attrib.enabled) + { + if (buffer) + { + BufferImpl *storage = buffer->getImplementation(); + input = static_cast<const char*>(storage->getData()) + static_cast<int>(attrib.offset); + } + else + { + input = static_cast<const char*>(attrib.pointer); + } + } + else + { + input = reinterpret_cast<const char*>(currentValue.FloatValues); + } + + if (instances == 0 || attrib.divisor == 0) + { + input += inputStride * start; + } + + gl::VertexFormat vertexFormat(attrib, currentValue.Type); + bool needsConversion = (d3d9::GetVertexConversionType(vertexFormat) & 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 + { + VertexCopyFunction copyFunction = d3d9::GetVertexCopyFunction(vertexFormat); + copyFunction(input, inputStride, count, mapPtr); + } + + mVertexBuffer->Unlock(); + + return true; + } + else + { + ERR("Vertex buffer not initialized."); + return false; + } +} + +bool VertexBuffer9::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, + unsigned int *outSpaceRequired) const +{ + return spaceRequired(attrib, count, instances, outSpaceRequired); +} + +unsigned int VertexBuffer9::getBufferSize() const +{ + return mBufferSize; +} + +bool VertexBuffer9::setBufferSize(unsigned int size) +{ + if (size > mBufferSize) + { + return initialize(size, mDynamicUsage); + } + else + { + return true; + } +} + +bool VertexBuffer9::discard() +{ + if (mVertexBuffer) + { + void *dummy; + HRESULT result; + + result = mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); + if (FAILED(result)) + { + ERR("Discard lock failed with error 0x%08x", result); + return false; + } + + result = mVertexBuffer->Unlock(); + if (FAILED(result)) + { + ERR("Discard unlock failed with error 0x%08x", result); + return false; + } + + return true; + } + else + { + ERR("Vertex buffer not initialized."); + return false; + } +} + +IDirect3DVertexBuffer9 * VertexBuffer9::getBuffer() const +{ + return mVertexBuffer; +} + +bool VertexBuffer9::spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, + unsigned int *outSpaceRequired) +{ + gl::VertexFormat vertexFormat(attrib, GL_FLOAT); + unsigned int elementSize = d3d9::GetVertexElementSize(vertexFormat); + + if (attrib.enabled) + { + unsigned int elementCount = 0; + if (instances == 0 || attrib.divisor == 0) + { + elementCount = count; + } + else + { + if (static_cast<unsigned int>(instances) < std::numeric_limits<unsigned int>::max() - (attrib.divisor - 1)) + { + // Round up + elementCount = (static_cast<unsigned int>(instances) + (attrib.divisor - 1)) / attrib.divisor; + } + else + { + elementCount = static_cast<unsigned int>(instances) / attrib.divisor; + } + } + + if (elementSize <= std::numeric_limits<unsigned int>::max() / elementCount) + { + if (outSpaceRequired) + { + *outSpaceRequired = elementSize * elementCount; + } + return true; + } + else + { + return false; + } + } + else + { + const unsigned int elementSize = 4; + if (outSpaceRequired) + { + *outSpaceRequired = elementSize * 4; + } + return true; + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h new file mode 100644 index 0000000000..fc4b6b6d26 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h @@ -0,0 +1,54 @@ +// +// 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 LIBGLESV2_RENDERER_VERTEXBUFFER9_H_ +#define LIBGLESV2_RENDERER_VERTEXBUFFER9_H_ + +#include "libGLESv2/renderer/d3d/VertexBuffer.h" + +namespace rx +{ +class Renderer9; + +class VertexBuffer9 : public VertexBuffer +{ + public: + explicit VertexBuffer9(rx::Renderer9 *const renderer); + virtual ~VertexBuffer9(); + + virtual bool initialize(unsigned int size, bool dynamicUsage); + + static VertexBuffer9 *makeVertexBuffer9(VertexBuffer *vertexBuffer); + + virtual bool storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset); + + virtual bool getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, unsigned int *outSpaceRequired) const; + + virtual unsigned int getBufferSize() const; + virtual bool setBufferSize(unsigned int size); + virtual bool discard(); + + IDirect3DVertexBuffer9 *getBuffer() const; + + private: + DISALLOW_COPY_AND_ASSIGN(VertexBuffer9); + + rx::Renderer9 *const mRenderer; + + IDirect3DVertexBuffer9 *mVertexBuffer; + unsigned int mBufferSize; + bool mDynamicUsage; + + static bool spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, + unsigned int *outSpaceRequired); +}; + +} + +#endif // LIBGLESV2_RENDERER_VERTEXBUFFER9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.cpp new file mode 100644 index 0000000000..303d8ad299 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.cpp @@ -0,0 +1,216 @@ +#include "precompiled.h" +// +// 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 "libGLESv2/ProgramBinary.h" +#include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h" +#include "libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h" +#include "libGLESv2/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); + } +} + +GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::ProgramBinary *programBinary, GLsizei instances, GLsizei *repeatDraw) +{ + *repeatDraw = 1; + + int indexedAttribute = gl::MAX_VERTEX_ATTRIBS; + int instancedAttribute = gl::MAX_VERTEX_ATTRIBS; + + if (instances > 0) + { + // Find an indexed attribute to be mapped to D3D stream 0 + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + if (attributes[i].active) + { + if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor == 0) + { + indexedAttribute = i; + } + else if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor != 0) + { + instancedAttribute = i; + } + if (indexedAttribute != gl::MAX_VERTEX_ATTRIBS && instancedAttribute != gl::MAX_VERTEX_ATTRIBS) + break; // Found both an indexed and instanced attribute + } + } + + if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS) + { + return GL_INVALID_OPERATION; + } + } + + D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1]; + D3DVERTEXELEMENT9 *element = &elements[0]; + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + if (attributes[i].active) + { + // Directly binding the storage buffer is not supported for d3d9 + ASSERT(attributes[i].storage == NULL); + + int stream = 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 == gl::MAX_VERTEX_ATTRIBS) + { + *repeatDraw = instances; + } + else + { + if (i == indexedAttribute) + { + stream = 0; + } + else if (i == 0) + { + stream = 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 = VertexBuffer9::makeVertexBuffer9(attributes[i].vertexBuffer); + + if (mAppliedVBs[stream].serial != attributes[i].serial || + mAppliedVBs[stream].stride != attributes[i].stride || + mAppliedVBs[stream].offset != attributes[i].offset) + { + device->SetStreamSource(stream, vertexBuffer->getBuffer(), attributes[i].offset, attributes[i].stride); + mAppliedVBs[stream].serial = attributes[i].serial; + mAppliedVBs[stream].stride = attributes[i].stride; + mAppliedVBs[stream].offset = attributes[i].offset; + } + + gl::VertexFormat vertexFormat(*attributes[i].attribute, GL_FLOAT); + + element->Stream = stream; + element->Offset = 0; + element->Type = d3d9::GetNativeVertexFormat(vertexFormat); + element->Method = D3DDECLMETHOD_DEFAULT; + element->Usage = D3DDECLUSAGE_TEXCOORD; + element->UsageIndex = programBinary->getSemanticIndex(i); + element++; + } + } + + if (instances == 0 || instancedAttribute == gl::MAX_VERTEX_ATTRIBS) + { + 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_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)); + device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration); + device->SetVertexDeclaration(lastCache->vertexDeclaration); + mLastSetVDecl = lastCache->vertexDeclaration; + lastCache->lruCount = ++mMaxLru; + + return 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/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h new file mode 100644 index 0000000000..004e28df4f --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h @@ -0,0 +1,58 @@ +// +// 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 LIBGLESV2_RENDERER_VERTEXDECLARATIONCACHE_H_ +#define LIBGLESV2_RENDERER_VERTEXDECLARATIONCACHE_H_ + +#include "libGLESv2/renderer/d3d/VertexDataManager.h" + +namespace gl +{ +class VertexDataManager; +} + +namespace rx +{ + +class VertexDeclarationCache +{ + public: + VertexDeclarationCache(); + ~VertexDeclarationCache(); + + GLenum applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::ProgramBinary *programBinary, 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 // LIBGLESV2_RENDERER_VERTEXDECLARATIONCACHE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp new file mode 100644 index 0000000000..f5d1da62b3 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp @@ -0,0 +1,820 @@ +#include "precompiled.h" +// +// 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 "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" +#include "libGLESv2/renderer/generatemip.h" +#include "libGLESv2/renderer/loadimage.h" +#include "libGLESv2/renderer/copyimage.h" +#include "libGLESv2/renderer/vertexconversion.h" + +namespace rx +{ + +// Each GL internal format corresponds to one D3D format and data loading function. +// Due to not all formats being available all the time, some of the function/format types are wrapped +// in templates that perform format support queries on a Renderer9 object which is supplied +// when requesting the function or format. + +typedef bool(*FallbackPredicateFunction)(); + +template <FallbackPredicateFunction pred, LoadImageFunction prefered, LoadImageFunction fallback> +static void FallbackLoad(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) +{ + if (pred()) + { + prefered(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); + } + else + { + fallback(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); + } +} + +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(); +} + +const D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Z'))); +const D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N', 'U', 'L', 'L'))); + +struct D3D9FormatInfo +{ + D3DFORMAT mTexFormat; + D3DFORMAT mRenderFormat; + LoadImageFunction mLoadFunction; + + D3D9FormatInfo() + : mTexFormat(D3DFMT_NULL), mRenderFormat(D3DFMT_NULL), mLoadFunction(NULL) + { } + + D3D9FormatInfo(D3DFORMAT textureFormat, D3DFORMAT renderFormat, LoadImageFunction loadFunc) + : mTexFormat(textureFormat), mRenderFormat(renderFormat), mLoadFunction(loadFunc) + { } +}; + +typedef std::pair<GLenum, D3D9FormatInfo> D3D9FormatPair; +typedef std::map<GLenum, D3D9FormatInfo> D3D9FormatMap; + +static D3D9FormatMap BuildD3D9FormatMap() +{ + D3D9FormatMap map; + + // | Internal format | Texture format | Render format | Load function | + map.insert(D3D9FormatPair(GL_NONE, D3D9FormatInfo(D3DFMT_NULL, D3DFMT_NULL, UnreachableLoad ))); + + map.insert(D3D9FormatPair(GL_DEPTH_COMPONENT16, D3D9FormatInfo(D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad ))); + map.insert(D3D9FormatPair(GL_DEPTH_COMPONENT32_OES, D3D9FormatInfo(D3DFMT_INTZ, D3DFMT_D32, UnreachableLoad ))); + map.insert(D3D9FormatPair(GL_DEPTH24_STENCIL8_OES, D3D9FormatInfo(D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad ))); + map.insert(D3D9FormatPair(GL_STENCIL_INDEX8, D3D9FormatInfo(D3DFMT_UNKNOWN, D3DFMT_D24S8, UnreachableLoad ))); // TODO: What's the texture format? + + map.insert(D3D9FormatPair(GL_RGBA32F_EXT, D3D9FormatInfo(D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative<GLfloat, 4> ))); + map.insert(D3D9FormatPair(GL_RGB32F_EXT, D3D9FormatInfo(D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative3To4<GLfloat, gl::Float32One>))); + map.insert(D3D9FormatPair(GL_RG32F_EXT, D3D9FormatInfo(D3DFMT_G32R32F, D3DFMT_G32R32F, LoadToNative<GLfloat, 2> ))); + map.insert(D3D9FormatPair(GL_R32F_EXT, D3D9FormatInfo(D3DFMT_R32F, D3DFMT_R32F, LoadToNative<GLfloat, 1> ))); + map.insert(D3D9FormatPair(GL_ALPHA32F_EXT, D3D9FormatInfo(D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadA32FToRGBA32F ))); + map.insert(D3D9FormatPair(GL_LUMINANCE32F_EXT, D3D9FormatInfo(D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadL32FToRGBA32F ))); + map.insert(D3D9FormatPair(GL_LUMINANCE_ALPHA32F_EXT, D3D9FormatInfo(D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadLA32FToRGBA32F ))); + + map.insert(D3D9FormatPair(GL_RGBA16F_EXT, D3D9FormatInfo(D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative<GLhalf, 4> ))); + map.insert(D3D9FormatPair(GL_RGB16F_EXT, D3D9FormatInfo(D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative3To4<GLhalf, gl::Float16One> ))); + map.insert(D3D9FormatPair(GL_RG16F_EXT, D3D9FormatInfo(D3DFMT_G16R16F, D3DFMT_G16R16F, LoadToNative<GLhalf, 2> ))); + map.insert(D3D9FormatPair(GL_R16F_EXT, D3D9FormatInfo(D3DFMT_R16F, D3DFMT_R16F, LoadToNative<GLhalf, 1> ))); + map.insert(D3D9FormatPair(GL_ALPHA16F_EXT, D3D9FormatInfo(D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadA16FToRGBA16F ))); + map.insert(D3D9FormatPair(GL_LUMINANCE16F_EXT, D3D9FormatInfo(D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadL16FToRGBA16F ))); + map.insert(D3D9FormatPair(GL_LUMINANCE_ALPHA16F_EXT, D3D9FormatInfo(D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadLA16FToRGBA16F ))); + + map.insert(D3D9FormatPair(GL_ALPHA8_EXT, D3D9FormatInfo(D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, FallbackLoad<gl::supportsSSE2, LoadA8ToBGRA8_SSE2, LoadA8ToBGRA8>))); + + map.insert(D3D9FormatPair(GL_RGB8_OES, D3D9FormatInfo(D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRGB8ToBGRX8 ))); + map.insert(D3D9FormatPair(GL_RGB565, D3D9FormatInfo(D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR5G6B5ToBGRA8 ))); + map.insert(D3D9FormatPair(GL_RGBA8_OES, D3D9FormatInfo(D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, FallbackLoad<gl::supportsSSE2, LoadRGBA8ToBGRA8_SSE2, LoadRGBA8ToBGRA8>))); + map.insert(D3D9FormatPair(GL_RGBA4, D3D9FormatInfo(D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGBA4ToBGRA8 ))); + map.insert(D3D9FormatPair(GL_RGB5_A1, D3D9FormatInfo(D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGB5A1ToBGRA8 ))); + map.insert(D3D9FormatPair(GL_R8_EXT, D3D9FormatInfo(D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR8ToBGRX8 ))); + map.insert(D3D9FormatPair(GL_RG8_EXT, D3D9FormatInfo(D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRG8ToBGRX8 ))); + + map.insert(D3D9FormatPair(GL_BGRA8_EXT, D3D9FormatInfo(D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadToNative<GLubyte, 4> ))); + map.insert(D3D9FormatPair(GL_BGRA4_ANGLEX, D3D9FormatInfo(D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGRA4ToBGRA8 ))); + map.insert(D3D9FormatPair(GL_BGR5_A1_ANGLEX, D3D9FormatInfo(D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGR5A1ToBGRA8 ))); + + map.insert(D3D9FormatPair(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, D3D9FormatInfo(D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 8> ))); + map.insert(D3D9FormatPair(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, D3D9FormatInfo(D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 8> ))); + map.insert(D3D9FormatPair(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, D3D9FormatInfo(D3DFMT_DXT3, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 16> ))); + map.insert(D3D9FormatPair(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, D3D9FormatInfo(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. + map.insert(D3D9FormatPair(GL_LUMINANCE8_EXT, D3D9FormatInfo(D3DFMT_L8, D3DFMT_UNKNOWN, LoadToNative<GLubyte, 1> ))); + map.insert(D3D9FormatPair(GL_LUMINANCE8_ALPHA8_EXT, D3D9FormatInfo(D3DFMT_A8L8, D3DFMT_UNKNOWN, LoadToNative<GLubyte, 2> ))); + + return map; +} + +static bool GetD3D9FormatInfo(GLenum internalFormat, D3D9FormatInfo *outFormatInfo) +{ + static const D3D9FormatMap formatMap = BuildD3D9FormatMap(); + D3D9FormatMap::const_iterator iter = formatMap.find(internalFormat); + if (iter != formatMap.end()) + { + if (outFormatInfo) + { + *outFormatInfo = iter->second; + } + return true; + } + else + { + return false; + } +} + +// A map to determine the pixel size and mip generation function of a given D3D format +struct D3DFormatInfo +{ + GLuint mPixelBits; + GLuint mBlockWidth; + GLuint mBlockHeight; + GLenum mInternalFormat; + + MipGenerationFunction mMipGenerationFunction; + ColorReadFunction mColorReadFunction; + + D3DFormatInfo() + : mPixelBits(0), mBlockWidth(0), mBlockHeight(0), mInternalFormat(GL_NONE), mMipGenerationFunction(NULL), + mColorReadFunction(NULL) + { } + + D3DFormatInfo(GLuint pixelBits, GLuint blockWidth, GLuint blockHeight, GLenum internalFormat, + MipGenerationFunction mipFunc, ColorReadFunction readFunc) + : mPixelBits(pixelBits), mBlockWidth(blockWidth), mBlockHeight(blockHeight), mInternalFormat(internalFormat), + mMipGenerationFunction(mipFunc), mColorReadFunction(readFunc) + { } +}; + +typedef std::pair<D3DFORMAT, D3DFormatInfo> D3D9FormatInfoPair; +typedef std::map<D3DFORMAT, D3DFormatInfo> D3D9FormatInfoMap; + +static D3D9FormatInfoMap BuildD3D9FormatInfoMap() +{ + D3D9FormatInfoMap map; + + // | D3DFORMAT | | S |W |H | Internal format | Mip generation function | Color read function | + map.insert(D3D9FormatInfoPair(D3DFMT_NULL, D3DFormatInfo( 0, 0, 0, GL_NONE, NULL, NULL ))); + map.insert(D3D9FormatInfoPair(D3DFMT_UNKNOWN, D3DFormatInfo( 0, 0, 0, GL_NONE, NULL, NULL ))); + + map.insert(D3D9FormatInfoPair(D3DFMT_L8, D3DFormatInfo( 8, 1, 1, GL_LUMINANCE8_EXT, GenerateMip<L8>, ReadColor<L8, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_A8, D3DFormatInfo( 8, 1, 1, GL_ALPHA8_EXT, GenerateMip<A8>, ReadColor<A8, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_A8L8, D3DFormatInfo( 16, 1, 1, GL_LUMINANCE8_ALPHA8_EXT, GenerateMip<A8L8>, ReadColor<A8L8, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_A4R4G4B4, D3DFormatInfo( 16, 1, 1, GL_BGRA4_ANGLEX, GenerateMip<B4G4R4A4>, ReadColor<B4G4R4A4, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_A1R5G5B5, D3DFormatInfo( 16, 1, 1, GL_BGR5_A1_ANGLEX, GenerateMip<B5G5R5A1>, ReadColor<B5G5R5A1, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_R5G6B5, D3DFormatInfo( 16, 1, 1, GL_RGB565, GenerateMip<R5G6B5>, ReadColor<R5G6B5, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_X8R8G8B8, D3DFormatInfo( 32, 1, 1, GL_BGRA8_EXT, GenerateMip<B8G8R8X8>, ReadColor<B8G8R8X8, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_A8R8G8B8, D3DFormatInfo( 32, 1, 1, GL_BGRA8_EXT, GenerateMip<B8G8R8A8>, ReadColor<B8G8R8A8, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_R16F, D3DFormatInfo( 16, 1, 1, GL_R16F_EXT, GenerateMip<R16F>, ReadColor<R16F, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_G16R16F, D3DFormatInfo( 32, 1, 1, GL_RG16F_EXT, GenerateMip<R16G16F>, ReadColor<R16G16F, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_A16B16G16R16F, D3DFormatInfo( 64, 1, 1, GL_RGBA16F_EXT, GenerateMip<R16G16B16A16F>, ReadColor<R16G16B16A16F, GLfloat>))); + map.insert(D3D9FormatInfoPair(D3DFMT_R32F, D3DFormatInfo( 32, 1, 1, GL_R32F_EXT, GenerateMip<R32F>, ReadColor<R32F, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_G32R32F, D3DFormatInfo( 64, 1, 1, GL_RG32F_EXT, GenerateMip<R32G32F>, ReadColor<R32G32F, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_A32B32G32R32F, D3DFormatInfo(128, 1, 1, GL_RGBA32F_EXT, GenerateMip<R32G32B32A32F>, ReadColor<R32G32B32A32F, GLfloat>))); + + map.insert(D3D9FormatInfoPair(D3DFMT_D16, D3DFormatInfo( 16, 1, 1, GL_DEPTH_COMPONENT16, NULL, NULL ))); + map.insert(D3D9FormatInfoPair(D3DFMT_D24S8, D3DFormatInfo( 32, 1, 1, GL_DEPTH24_STENCIL8_OES, NULL, NULL ))); + map.insert(D3D9FormatInfoPair(D3DFMT_D24X8, D3DFormatInfo( 32, 1, 1, GL_DEPTH_COMPONENT16, NULL, NULL ))); + map.insert(D3D9FormatInfoPair(D3DFMT_D32, D3DFormatInfo( 32, 1, 1, GL_DEPTH_COMPONENT32_OES, NULL, NULL ))); + + map.insert(D3D9FormatInfoPair(D3DFMT_INTZ, D3DFormatInfo( 32, 1, 1, GL_DEPTH24_STENCIL8_OES, NULL, NULL ))); + + map.insert(D3D9FormatInfoPair(D3DFMT_DXT1, D3DFormatInfo( 64, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, NULL, NULL ))); + map.insert(D3D9FormatInfoPair(D3DFMT_DXT3, D3DFormatInfo(128, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, NULL, NULL ))); + map.insert(D3D9FormatInfoPair(D3DFMT_DXT5, D3DFormatInfo(128, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, NULL, NULL ))); + + return map; +} + +static const D3D9FormatInfoMap &GetD3D9FormatInfoMap() +{ + static const D3D9FormatInfoMap infoMap = BuildD3D9FormatInfoMap(); + return infoMap; +} + +static bool GetD3D9FormatInfo(D3DFORMAT format, D3DFormatInfo *outFormatInfo) +{ + const D3D9FormatInfoMap &infoMap = GetD3D9FormatInfoMap(); + D3D9FormatInfoMap::const_iterator iter = infoMap.find(format); + if (iter != infoMap.end()) + { + if (outFormatInfo) + { + *outFormatInfo = iter->second; + } + return true; + } + else + { + return false; + } +} +static d3d9::D3DFormatSet BuildAllD3DFormatSet() +{ + d3d9::D3DFormatSet set; + + const D3D9FormatInfoMap &infoMap = GetD3D9FormatInfoMap(); + for (D3D9FormatInfoMap::const_iterator i = infoMap.begin(); i != infoMap.end(); ++i) + { + set.insert(i->first); + } + + return set; +} + +struct D3D9FastCopyFormat +{ + D3DFORMAT mSourceFormat; + GLenum mDestFormat; + GLenum mDestType; + + D3D9FastCopyFormat(D3DFORMAT sourceFormat, GLenum destFormat, GLenum destType) + : mSourceFormat(sourceFormat), mDestFormat(destFormat), mDestType(destType) + { } + + bool operator<(const D3D9FastCopyFormat& other) const + { + return memcmp(this, &other, sizeof(D3D9FastCopyFormat)) < 0; + } +}; + +typedef std::map<D3D9FastCopyFormat, ColorCopyFunction> D3D9FastCopyMap; +typedef std::pair<D3D9FastCopyFormat, ColorCopyFunction> D3D9FastCopyPair; + +static D3D9FastCopyMap BuildFastCopyMap() +{ + D3D9FastCopyMap map; + + map.insert(D3D9FastCopyPair(D3D9FastCopyFormat(D3DFMT_A8R8G8B8, GL_RGBA, GL_UNSIGNED_BYTE), CopyBGRAUByteToRGBAUByte)); + + return map; +} + +typedef std::pair<GLint, InitializeTextureDataFunction> InternalFormatInitialzerPair; +typedef std::map<GLint, InitializeTextureDataFunction> InternalFormatInitialzerMap; + +static InternalFormatInitialzerMap BuildInternalFormatInitialzerMap() +{ + 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 const InternalFormatInitialzerMap &GetInternalFormatInitialzerMap() +{ + static const InternalFormatInitialzerMap map = BuildInternalFormatInitialzerMap(); + return map; +} + +namespace d3d9 +{ + +MipGenerationFunction GetMipGenerationFunction(D3DFORMAT format) +{ + D3DFormatInfo d3dFormatInfo; + if (GetD3D9FormatInfo(format, &d3dFormatInfo)) + { + return d3dFormatInfo.mMipGenerationFunction; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +LoadImageFunction GetImageLoadFunction(GLenum internalFormat) +{ + D3D9FormatInfo d3d9FormatInfo; + if (GetD3D9FormatInfo(internalFormat, &d3d9FormatInfo)) + { + return d3d9FormatInfo.mLoadFunction; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +GLuint GetFormatPixelBytes(D3DFORMAT format) +{ + D3DFormatInfo d3dFormatInfo; + if (GetD3D9FormatInfo(format, &d3dFormatInfo)) + { + return d3dFormatInfo.mPixelBits / 8; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetBlockWidth(D3DFORMAT format) +{ + D3DFormatInfo d3dFormatInfo; + if (GetD3D9FormatInfo(format, &d3dFormatInfo)) + { + return d3dFormatInfo.mBlockWidth; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetBlockHeight(D3DFORMAT format) +{ + D3DFormatInfo d3dFormatInfo; + if (GetD3D9FormatInfo(format, &d3dFormatInfo)) + { + return d3dFormatInfo.mBlockHeight; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetBlockSize(D3DFORMAT format, GLuint width, GLuint height) +{ + D3DFormatInfo d3dFormatInfo; + if (GetD3D9FormatInfo(format, &d3dFormatInfo)) + { + GLuint numBlocksWide = (width + d3dFormatInfo.mBlockWidth - 1) / d3dFormatInfo.mBlockWidth; + GLuint numBlocksHight = (height + d3dFormatInfo.mBlockHeight - 1) / d3dFormatInfo.mBlockHeight; + + return (d3dFormatInfo.mPixelBits * numBlocksWide * numBlocksHight) / 8; + } + else + { + UNREACHABLE(); + return 0; + } +} + +void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset) +{ + D3DFormatInfo d3dFormatInfo; + if (GetD3D9FormatInfo(format, &d3dFormatInfo)) + { + int upsampleCount = 0; + + GLsizei blockWidth = d3dFormatInfo.mBlockWidth; + GLsizei blockHeight = d3dFormatInfo.mBlockHeight; + + // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already. + if (isImage || *requestWidth < blockWidth || *requestHeight < blockHeight) + { + while (*requestWidth % blockWidth != 0 || *requestHeight % blockHeight != 0) + { + *requestWidth <<= 1; + *requestHeight <<= 1; + upsampleCount++; + } + } + *levelOffset = upsampleCount; + } +} + +const D3DFormatSet &GetAllUsedD3DFormats() +{ + static const D3DFormatSet formatSet = BuildAllD3DFormatSet(); + return formatSet; +} + +ColorReadFunction GetColorReadFunction(D3DFORMAT format) +{ + D3DFormatInfo d3dFormatInfo; + if (GetD3D9FormatInfo(format, &d3dFormatInfo)) + { + return d3dFormatInfo.mColorReadFunction; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +ColorCopyFunction GetFastCopyFunction(D3DFORMAT sourceFormat, GLenum destFormat, GLenum destType) +{ + static const D3D9FastCopyMap fastCopyMap = BuildFastCopyMap(); + D3D9FastCopyMap::const_iterator iter = fastCopyMap.find(D3D9FastCopyFormat(sourceFormat, destFormat, destType)); + return (iter != fastCopyMap.end()) ? iter->second : NULL; +} + +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 FormatConverter +{ + bool identity; + std::size_t outputElementSize; + void (*convertArray)(const void *in, std::size_t stride, std::size_t n, void *out); + D3DDECLTYPE d3dDeclType; +}; + +struct TranslationDescription +{ + DWORD capsFlag; + FormatConverter preferredConversion; + FormatConverter fallbackConversion; +}; + +static unsigned int typeIndex(GLenum type); +static const FormatConverter &formatConverter(const gl::VertexAttribute &attribute); + +bool mTranslationsInitialized = false; +FormatConverter mFormatConverters[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; + +// 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 }; +}; + +// Initialize a TranslationInfo +#define TRANSLATION(type, norm, size, preferred) \ + { \ + 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) }, \ + } + +const TranslationDescription mPossibleTranslations[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) +}; + +void InitializeVertexTranslations(const rx::Renderer9 *renderer) +{ + DWORD declTypes = renderer->getCapsDeclTypes(); + + 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 (mPossibleTranslations[i][j][k].capsFlag == 0 || (declTypes & mPossibleTranslations[i][j][k].capsFlag) != 0) + { + mFormatConverters[i][j][k] = mPossibleTranslations[i][j][k].preferredConversion; + } + else + { + mFormatConverters[i][j][k] = mPossibleTranslations[i][j][k].fallbackConversion; + } + } + } + } +} + +unsigned int typeIndex(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 FormatConverter &formatConverter(const gl::VertexFormat &vertexFormat) +{ + // Pure integer attributes only supported in ES3.0 + ASSERT(!vertexFormat.mPureInteger); + return mFormatConverters[typeIndex(vertexFormat.mType)][vertexFormat.mNormalized][vertexFormat.mComponents - 1]; +} + +VertexCopyFunction GetVertexCopyFunction(const gl::VertexFormat &vertexFormat) +{ + return formatConverter(vertexFormat).convertArray; +} + +size_t GetVertexElementSize(const gl::VertexFormat &vertexFormat) +{ + return formatConverter(vertexFormat).outputElementSize; +} + +VertexConversionType GetVertexConversionType(const gl::VertexFormat &vertexFormat) +{ + return (formatConverter(vertexFormat).identity ? VERTEX_CONVERT_NONE : VERTEX_CONVERT_CPU); +} + +D3DDECLTYPE GetNativeVertexFormat(const gl::VertexFormat &vertexFormat) +{ + return formatConverter(vertexFormat).d3dDeclType; +} + +} + +namespace gl_d3d9 +{ + +D3DFORMAT GetTextureFormat(GLenum internalFormat) +{ + D3D9FormatInfo d3d9FormatInfo; + if (GetD3D9FormatInfo(internalFormat, &d3d9FormatInfo)) + { + return d3d9FormatInfo.mTexFormat; + } + else + { + return D3DFMT_UNKNOWN; + } +} + +D3DFORMAT GetRenderFormat(GLenum internalFormat) +{ + D3D9FormatInfo d3d9FormatInfo; + if (GetD3D9FormatInfo(internalFormat, &d3d9FormatInfo)) + { + return d3d9FormatInfo.mRenderFormat; + } + else + { + return D3DFMT_UNKNOWN; + } +} + +D3DMULTISAMPLE_TYPE GetMultisampleType(GLsizei samples) +{ + return (samples > 1) ? static_cast<D3DMULTISAMPLE_TYPE>(samples) : D3DMULTISAMPLE_NONE; +} + +bool RequiresTextureDataInitialization(GLint internalFormat) +{ + const InternalFormatInitialzerMap &map = GetInternalFormatInitialzerMap(); + return map.find(internalFormat) != map.end(); +} + +InitializeTextureDataFunction GetTextureDataInitializationFunction(GLint internalFormat) +{ + const InternalFormatInitialzerMap &map = GetInternalFormatInitialzerMap(); + InternalFormatInitialzerMap::const_iterator iter = map.find(internalFormat); + if (iter != map.end()) + { + return iter->second; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +} + +namespace d3d9_gl +{ + +GLenum GetInternalFormat(D3DFORMAT format) +{ + static const D3D9FormatInfoMap infoMap = BuildD3D9FormatInfoMap(); + D3D9FormatInfoMap::const_iterator iter = infoMap.find(format); + if (iter != infoMap.end()) + { + return iter->second.mInternalFormat; + } + else + { + UNREACHABLE(); + return GL_NONE; + } +} + +GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type) +{ + return (type != D3DMULTISAMPLE_NONMASKABLE) ? type : 0; +} + +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format) +{ + GLenum internalFormat = d3d9_gl::GetInternalFormat(d3dformat); + GLenum convertedFormat = gl::GetFormat(internalFormat); + return convertedFormat == format; +} + +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.h new file mode 100644 index 0000000000..26388794e0 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.h @@ -0,0 +1,77 @@ +// +// 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 LIBGLESV2_RENDERER_FORMATUTILS9_H_ +#define LIBGLESV2_RENDERER_FORMATUTILS9_H_ + +#include "libGLESv2/formatutils.h" + +namespace rx +{ + +class Renderer9; + +namespace d3d9 +{ + +typedef std::set<D3DFORMAT> D3DFormatSet; + +MipGenerationFunction GetMipGenerationFunction(D3DFORMAT format); +LoadImageFunction GetImageLoadFunction(GLenum internalFormat); + +GLuint GetFormatPixelBytes(D3DFORMAT format); +GLuint GetBlockWidth(D3DFORMAT format); +GLuint GetBlockHeight(D3DFORMAT format); +GLuint GetBlockSize(D3DFORMAT format, GLuint width, GLuint height); + +void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset); + +const D3DFormatSet &GetAllUsedD3DFormats(); + +ColorReadFunction GetColorReadFunction(D3DFORMAT format); +ColorCopyFunction GetFastCopyFunction(D3DFORMAT sourceFormat, GLenum destFormat, GLenum destType); + +VertexCopyFunction GetVertexCopyFunction(const gl::VertexFormat &vertexFormat); +size_t GetVertexElementSize(const gl::VertexFormat &vertexFormat); +VertexConversionType GetVertexConversionType(const gl::VertexFormat &vertexFormat); +D3DDECLTYPE GetNativeVertexFormat(const gl::VertexFormat &vertexFormat); + +GLenum GetDeclTypeComponentType(D3DDECLTYPE declType); +int GetDeclTypeComponentCount(D3DDECLTYPE declType); +bool IsDeclTypeNormalized(D3DDECLTYPE declType); + +void InitializeVertexTranslations(const rx::Renderer9 *renderer); + +} + +namespace gl_d3d9 +{ + +D3DFORMAT GetTextureFormat(GLenum internalForma); +D3DFORMAT GetRenderFormat(GLenum internalFormat); + +D3DMULTISAMPLE_TYPE GetMultisampleType(GLsizei samples); + +bool RequiresTextureDataInitialization(GLint internalFormat); +InitializeTextureDataFunction GetTextureDataInitializationFunction(GLint internalFormat); + +} + +namespace d3d9_gl +{ + +GLenum GetInternalFormat(D3DFORMAT format); +GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type); +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format); + +} + +} + +#endif // LIBGLESV2_RENDERER_FORMATUTILS9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp new file mode 100644 index 0000000000..68e5378fbb --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp @@ -0,0 +1,409 @@ +#include "precompiled.h" +// +// 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 "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/formatutils.h" +#include "common/mathutil.h" +#include "libGLESv2/Context.h" + +#include "common/debug.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 maxAnisotropy) +{ + 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(); + } + + if (maxAnisotropy > 1.0f) + { + *d3dMinFilter = D3DTEXF_ANISOTROPIC; + } +} + +} + +namespace d3d9_gl +{ + +static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, IDirect3D9 *d3d9, D3DDEVTYPE deviceType, + UINT adapter, D3DFORMAT adapterFormat) +{ + gl::TextureCaps textureCaps; + + D3DFORMAT renderFormat = gl_d3d9::GetRenderFormat(internalFormat); + if (gl::GetDepthBits(internalFormat) > 0 || gl::GetStencilBits(internalFormat) > 0) + { + textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, renderFormat)); + textureCaps.filterable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, renderFormat)); + textureCaps.renderable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, renderFormat)) || + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, renderFormat)); + } + else + { + D3DFORMAT textureFormat = gl_d3d9::GetTextureFormat(internalFormat); + textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, textureFormat)) && + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_CUBETEXTURE, textureFormat)); + textureCaps.filterable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, textureFormat)); + textureCaps.renderable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, textureFormat)) || + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, textureFormat)); + } + + textureCaps.sampleCounts.insert(1); + for (size_t i = D3DMULTISAMPLE_2_SAMPLES; i <= D3DMULTISAMPLE_16_SAMPLES; i++) + { + D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_TYPE(i); + + HRESULT result = d3d9->CheckDeviceMultiSampleType(adapter, deviceType, 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) +{ + D3DCAPS9 deviceCaps; + if (FAILED(d3d9->GetDeviceCaps(adapter, deviceType, &deviceCaps))) + { + // Can't continue with out device caps + return; + } + + D3DDISPLAYMODE currentDisplayMode; + d3d9->GetAdapterDisplayMode(adapter, ¤tDisplayMode); + + 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); + } + + // 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; + + // GL extension support + extensions->setTextureExtensionSupport(*textureCapsMap); + extensions->elementIndexUint = deviceCaps.MaxVertexIndex >= (1 << 16); + extensions->packedDepthStencil = true; + extensions->getProgramBinary = true; + extensions->rgb8rgba8 = true; + extensions->readFormatBGRA = true; + extensions->pixelBufferObject = false; + extensions->mapBuffer = false; + extensions->mapBufferRange = false; + + // ATI cards on XP have problems with non-power-of-two textures. + D3DADAPTER_IDENTIFIER9 adapterId = { 0 }; + if (SUCCEEDED(d3d9->GetAdapterIdentifier(adapter, 0, &adapterId))) + { + extensions->textureNPOT = !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) && + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && + !(isWindowsVistaOrGreater() && adapterId.VendorId == VENDOR_ID_AMD); + } + 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->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->colorBufferFloat = false; +} + +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.h new file mode 100644 index 0000000000..7f3c65d3e0 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.h @@ -0,0 +1,65 @@ +// +// 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 LIBGLESV2_RENDERER_RENDERER9_UTILS_H +#define LIBGLESV2_RENDERER_RENDERER9_UTILS_H + +#include "libGLESv2/angletypes.h" +#include "libGLESv2/Caps.h" + +namespace rx +{ + +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 maxAnisotropy); + +} + +namespace d3d9_gl +{ + +void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceType, UINT adapter, gl::Caps *caps, + gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions); + +} + +namespace d3d9 +{ + +inline bool isDeviceLostError(HRESULT errorCode) +{ + switch (errorCode) + { + case D3DERR_DRIVERINTERNALERROR: + case D3DERR_DEVICELOST: + case D3DERR_DEVICEHUNG: + case D3DERR_DEVICEREMOVED: + return true; + default: + return false; + } +} + +} + +} + +#endif // LIBGLESV2_RENDERER_RENDERER9_UTILS_H diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps new file mode 100644 index 0000000000..eb43eb3e7a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/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 PS_passthrough(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 PS_luminance(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 PS_componentmask(float4 texcoord : TEXCOORD0) : COLOR +{ + return tex2D(tex, texcoord.xy) * mult + add; +}; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.vs b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.vs new file mode 100644 index 0000000000..3bd611ba5d --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/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 VS_standard(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 VS_flipy(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; +}; |