diff options
Diffstat (limited to 'src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9')
34 files changed, 8957 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..f061a32c52 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp @@ -0,0 +1,644 @@ +// +// 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/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" +#include "libGLESv2/main.h" + +namespace +{ +// Precompiled shaders +#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::copy2D(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level) +{ + RenderTarget9 *renderTarget = NULL; + IDirect3DSurface9 *source = NULL; + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); + + if (colorbuffer) + { + renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer); + } + + 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); + 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::copyCube(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level) +{ + RenderTarget9 *renderTarget = NULL; + IDirect3DSurface9 *source = NULL; + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); + + if (colorbuffer) + { + renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer); + } + + 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); + 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..46a3ee1cf3 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h @@ -0,0 +1,95 @@ +// +// 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" + +#include <GLES2/gl2.h> + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ +class Renderer9; +class TextureStorage; + +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 copy2D(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level); + bool copyCube(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level); + + // Copy from source surface to dest surface. + // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) + // source is interpreted as RGBA and destFormat specifies the desired result format. For example, if destFormat = GL_RGB, the alpha channel will be forced to 0. + 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..c02db515a2 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp @@ -0,0 +1,121 @@ +// +// 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/renderer/d3d/d3d9/Renderer9.h" +#include "libGLESv2/main.h" + +namespace rx +{ + +Buffer9::Buffer9(rx::Renderer9 *renderer) + : BufferD3D(), + mRenderer(renderer), + mSize(0) +{} + +Buffer9::~Buffer9() +{ + mSize = 0; +} + +Buffer9 *Buffer9::makeBuffer9(BufferImpl *buffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(Buffer9*, buffer)); + return static_cast<Buffer9*>(buffer); +} + +gl::Error 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, "Failed to resize internal buffer."); + } + } + + mSize = size; + if (data) + { + memcpy(mMemory.data(), data, size); + } + + invalidateStaticData(); + + if (usage == GL_STATIC_DRAW) + { + initializeStaticData(); + } + + return gl::Error(GL_NO_ERROR); +} + +void *Buffer9::getData() +{ + return mMemory.data(); +} + +gl::Error 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, "Failed to resize internal buffer."); + } + } + + mSize = std::max(mSize, offset + size); + if (data) + { + memcpy(mMemory.data() + offset, data, size); + } + + invalidateStaticData(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer9::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) +{ + // Note: this method is currently unreachable + Buffer9* sourceBuffer = makeBuffer9(source); + ASSERT(sourceBuffer); + + memcpy(mMemory.data() + destOffset, sourceBuffer->mMemory.data() + sourceOffset, size); + + invalidateStaticData(); + + return gl::Error(GL_NO_ERROR); +} + +// We do not support buffer mapping in D3D9 +gl::Error Buffer9::map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) +{ + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +gl::Error Buffer9::unmap() +{ + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +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..e78182f905 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.h @@ -0,0 +1,52 @@ +// +// 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 bool supportsDirectBinding() const { return false; } + virtual Renderer* getRenderer(); + + // BufferImpl implementation + virtual gl::Error setData(const void* data, size_t size, GLenum usage); + virtual void *getData(); + virtual gl::Error setSubData(const void* data, size_t size, size_t offset); + virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); + virtual gl::Error map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr); + virtual gl::Error 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..e352a5f50a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp @@ -0,0 +1,72 @@ +// +// 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/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" +#include "libGLESv2/main.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..18383fba78 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp @@ -0,0 +1,706 @@ +// +// 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/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" +#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" +#include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h" +#include "libGLESv2/main.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" +#include "libGLESv2/Renderbuffer.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); + + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(sourceDesc.Format); + ASSERT(d3dFormatInfo.mipGenerationFunction != 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) + { + d3dFormatInfo.mipGenerationFunction(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); + + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); + unsigned int rows = desc.Height / d3dFormatInfo.blockHeight; + + unsigned int bytes = d3d9::ComputeBlockSize(desc.Format, desc.Width, d3dFormatInfo.blockHeight); + ASSERT(bytes <= static_cast<unsigned int>(sourceLock.Pitch) && + bytes <= static_cast<unsigned int>(destLock.Pitch)); + + for(unsigned int i = 0; i < rows; i++) + { + memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes); + } + + source->UnlockRect(); + dest->UnlockRect(); + } + 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 + const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(internalformat); + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat); + mD3DFormat = d3d9FormatInfo.texFormat; + mActualFormat = d3dFormatInfo.internalFormat; + mRenderable = (d3d9FormatInfo.renderFormat != D3DFMT_UNKNOWN); + + SafeRelease(mSurface); + mDirty = (d3d9FormatInfo.dataInitializerFunction != NULL); + + 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); + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); + if (d3dFormatInfo.dataInitializerFunction != NULL) + { + RECT entireRect; + entireRect.left = 0; + entireRect.right = mWidth; + entireRect.top = 0; + entireRect.bottom = mHeight; + + D3DLOCKED_RECT lockedRect; + result = newSurface->LockRect(&lockedRect, &entireRect, 0); + ASSERT(SUCCEEDED(result)); + + d3dFormatInfo.dataInitializerFunction(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 || d3d9::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL) && mDirty; +} + +IDirect3DSurface9 *Image9::getSurface() +{ + createSurface(); + + return mSurface; +} + +void Image9::setManagedSurface2D(TextureStorage *storage, int level) +{ + TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); + setManagedSurface(storage9->getSurfaceLevel(level, false)); +} + +void Image9::setManagedSurfaceCube(TextureStorage *storage, int face, int level) +{ + TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); + 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::copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + ASSERT(getSurface() != NULL); + TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); + return copyToSurface(storage9->getSurfaceLevel(level, true), xoffset, yoffset, width, height); +} + +bool Image9::copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + ASSERT(getSurface() != NULL); + TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); + return copyToSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true), xoffset, yoffset, width, height); +} + +bool Image9::copyToStorage3D(TextureStorage *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::copyToStorage2DArray(TextureStorage *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); + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); + GLsizei inputRowPitch = formatInfo.computeRowPitch(type, width, unpackAlignment); + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); + ASSERT(d3dFormatInfo.loadFunction != NULL); + + RECT lockRect = + { + xoffset, yoffset, + xoffset + width, yoffset + height + }; + + D3DLOCKED_RECT locked; + HRESULT result = lock(&locked, &lockRect); + if (FAILED(result)) + { + return; + } + + d3dFormatInfo.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); + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); + GLsizei inputRowPitch = formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, width, 1); + GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1); + + const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); + + ASSERT(xoffset % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockWidth == 0); + ASSERT(yoffset % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockHeight == 0); + + ASSERT(d3d9FormatInfo.loadFunction != NULL); + + RECT lockRect = + { + xoffset, yoffset, + xoffset + width, yoffset + height + }; + + D3DLOCKED_RECT locked; + HRESULT result = lock(&locked, &lockRect); + if (FAILED(result)) + { + return; + } + + d3d9FormatInfo.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 = d3d9::GetAttachmentRenderTarget(colorbuffer); + } + + 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..08d8ee3545 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h @@ -0,0 +1,78 @@ +// +// 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 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 setManagedSurface2D(TextureStorage *storage, int level); + virtual void setManagedSurfaceCube(TextureStorage *storage, int face, int level); + virtual bool copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + virtual bool copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + virtual bool copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); + virtual bool copyToStorage2DArray(TextureStorage *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..1c51b9e985 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.cpp @@ -0,0 +1,173 @@ +// +// 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); +} + +gl::Error IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) +{ + SafeRelease(mIndexBuffer); + + updateSerial(); + + if (bufferSize > 0) + { + D3DFORMAT format = D3DFMT_UNKNOWN; + if (indexType == GL_UNSIGNED_SHORT || indexType == GL_UNSIGNED_BYTE) + { + format = D3DFMT_INDEX16; + } + else if (indexType == GL_UNSIGNED_INT) + { + ASSERT(mRenderer->getRendererExtensions().elementIndexUint); + format = D3DFMT_INDEX32; + } + else UNREACHABLE(); + + DWORD usageFlags = D3DUSAGE_WRITEONLY; + if (dynamic) + { + usageFlags |= D3DUSAGE_DYNAMIC; + } + + HRESULT result = mRenderer->createIndexBuffer(bufferSize, usageFlags, format, &mIndexBuffer); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal index buffer of size, %lu.", bufferSize); + } + } + + mBufferSize = bufferSize; + mIndexType = indexType; + mDynamic = dynamic; + + return gl::Error(GL_NO_ERROR); +} + +IndexBuffer9 *IndexBuffer9::makeIndexBuffer9(IndexBuffer *indexBuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(IndexBuffer9*, indexBuffer)); + return static_cast<IndexBuffer9*>(indexBuffer); +} + +gl::Error IndexBuffer9::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory) +{ + if (!mIndexBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + } + + DWORD lockFlags = mDynamic ? D3DLOCK_NOOVERWRITE : 0; + + void *mapPtr = NULL; + HRESULT result = mIndexBuffer->Lock(offset, size, &mapPtr, lockFlags); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal index buffer, HRESULT: 0x%08x.", result); + } + + *outMappedMemory = mapPtr; + return gl::Error(GL_NO_ERROR); +} + +gl::Error IndexBuffer9::unmapBuffer() +{ + if (!mIndexBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + } + + HRESULT result = mIndexBuffer->Unlock(); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal index buffer, HRESULT: 0x%08x.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +GLenum IndexBuffer9::getIndexType() const +{ + return mIndexType; +} + +unsigned int IndexBuffer9::getBufferSize() const +{ + return mBufferSize; +} + +gl::Error IndexBuffer9::setSize(unsigned int bufferSize, GLenum indexType) +{ + if (bufferSize > mBufferSize || indexType != mIndexType) + { + return initialize(bufferSize, indexType, mDynamic); + } + else + { + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error IndexBuffer9::discard() +{ + if (!mIndexBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + } + + void *dummy; + HRESULT result; + + result = mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal index buffer, HRESULT: 0x%08x.", result); + } + + result = mIndexBuffer->Unlock(); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal index buffer, HRESULT: 0x%08x.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +D3DFORMAT IndexBuffer9::getIndexFormat() const +{ + switch (mIndexType) + { + case GL_UNSIGNED_BYTE: return D3DFMT_INDEX16; + case GL_UNSIGNED_SHORT: return D3DFMT_INDEX16; + case GL_UNSIGNED_INT: return D3DFMT_INDEX32; + default: UNREACHABLE(); return D3DFMT_UNKNOWN; + } +} + +IDirect3DIndexBuffer9 * IndexBuffer9::getBuffer() const +{ + return mIndexBuffer; +} + +} diff --git a/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..d0970d6ac5 --- /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 gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic); + + static IndexBuffer9 *makeIndexBuffer9(IndexBuffer *indexBuffer); + + virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory); + virtual gl::Error unmapBuffer(); + + virtual GLenum getIndexType() const; + virtual unsigned int getBufferSize() const; + virtual gl::Error setSize(unsigned int bufferSize, GLenum indexType); + + virtual gl::Error discard(); + + D3DFORMAT getIndexFormat() const; + IDirect3DIndexBuffer9 *getBuffer() const; + + private: + 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..815fc01a9b --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.cpp @@ -0,0 +1,144 @@ +// +// 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/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" +#include "libGLESv2/main.h" + +#include <GLES2/gl2ext.h> + +namespace rx +{ +Query9::Query9(rx::Renderer9 *renderer, GLenum type) + : QueryImpl(type), + mResult(GL_FALSE), + mQueryFinished(false), + mRenderer(renderer), + mQuery(NULL) +{ +} + +Query9::~Query9() +{ + SafeRelease(mQuery); +} + +gl::Error Query9::begin() +{ + if (mQuery == NULL) + { + HRESULT result = mRenderer->getDevice()->CreateQuery(D3DQUERYTYPE_OCCLUSION, &mQuery); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", result); + } + } + + HRESULT result = mQuery->Issue(D3DISSUE_BEGIN); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to begin internal query, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query9::end() +{ + ASSERT(mQuery); + + HRESULT result = mQuery->Issue(D3DISSUE_END); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to end internal query, result: 0x%X.", result); + } + + mQueryFinished = false; + mResult = GL_FALSE; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query9::getResult(GLuint *params) +{ + while (!mQueryFinished) + { + gl::Error error = testQuery(); + if (error.isError()) + { + return error; + } + + if (!mQueryFinished) + { + Sleep(0); + } + } + + ASSERT(mQueryFinished); + *params = mResult; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query9::isResultAvailable(GLuint *available) +{ + gl::Error error = testQuery(); + if (error.isError()) + { + return error; + } + + *available = (mQueryFinished ? GL_TRUE : GL_FALSE); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query9::testQuery() +{ + if (!mQueryFinished) + { + ASSERT(mQuery); + + DWORD numPixels = 0; + + HRESULT hres = mQuery->GetData(&numPixels, sizeof(DWORD), D3DGETDATA_FLUSH); + if (hres == S_OK) + { + mQueryFinished = 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: + UNREACHABLE(); + break; + } + } + else if (d3d9::isDeviceLostError(hres)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost."); + } + else if (mRenderer->testDeviceLost(true)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost."); + } + } + + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/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..513e0ba6fd --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.h @@ -0,0 +1,43 @@ +// +// 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 gl::Error begin(); + virtual gl::Error end(); + virtual gl::Error getResult(GLuint *params); + virtual gl::Error isResultAvailable(GLuint *available); + + private: + DISALLOW_COPY_AND_ASSIGN(Query9); + + gl::Error testQuery(); + + GLuint mResult; + bool mQueryFinished; + + 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..13321ac8cd --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp @@ -0,0 +1,133 @@ +// +// 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; + + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(description.Format); + mInternalFormat = d3dFormatInfo.internalFormat; + mActualFormat = d3dFormatInfo.internalFormat; + mSamples = d3d9_gl::GetSamplesCount(description.MultiSampleType); + } +} + +RenderTarget9::RenderTarget9(Renderer *renderer, GLsizei width, GLsizei height, GLenum internalFormat, GLsizei samples) +{ + mRenderer = Renderer9::makeRenderer9(renderer); + mRenderTarget = NULL; + + const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(internalFormat); + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(d3d9FormatInfo.renderFormat); + + const gl::TextureCaps &textureCaps = mRenderer->getRendererTextureCaps().get(internalFormat); + GLuint supportedSamples = textureCaps.getNearestSamples(samples); + + HRESULT result = D3DERR_INVALIDCALL; + + if (width > 0 && height > 0) + { + IDirect3DDevice9 *device = mRenderer->getDevice(); + + bool requiresInitialization = false; + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + result = device->CreateDepthStencilSurface(width, height, d3d9FormatInfo.renderFormat, + gl_d3d9::GetMultisampleType(supportedSamples), + 0, FALSE, &mRenderTarget, NULL); + } + else + { + requiresInitialization = (d3d9FormatInfo.dataInitializerFunction != NULL); + result = device->CreateRenderTarget(width, height, d3d9FormatInfo.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 = d3dFormatInfo.internalFormat; +} + +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..d63f9b8582 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp @@ -0,0 +1,3131 @@ +// +// 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 "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/renderer/d3d/IndexDataManager.h" +#include "libGLESv2/renderer/d3d/ProgramD3D.h" +#include "libGLESv2/renderer/d3d/ShaderD3D.h" +#include "libGLESv2/renderer/d3d/TextureD3D.h" +#include "libGLESv2/renderer/d3d/TransformFeedbackD3D.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/angletypes.h" + +#include "libEGL/Display.h" + +#include "common/utilities.h" + +#include <sstream> + +// 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; + + mMaskedClearSavedState = NULL; + + mVertexDataManager = NULL; + mIndexDataManager = NULL; + mLineLoopIB = NULL; + mCountingIB = NULL; + + mMaxNullColorbufferLRU = 0; + for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) + { + mNullColorbufferCache[i].lruCount = 0; + mNullColorbufferCache[i].width = 0; + mNullColorbufferCache[i].height = 0; + mNullColorbufferCache[i].buffer = NULL; + } + + mAppliedVertexShader = NULL; + mAppliedPixelShader = NULL; + mAppliedProgramSerial = 0; +} + +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() +{ + releaseShaderCompiler(); + 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; + } + + 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))) + { + ASSERT(mD3d9Ex); + mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast<void**>(&mD3d9)); + ASSERT(mD3d9); + } + else + { + 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. + { + 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; + } + + { + 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); + } + + static const TCHAR windowName[] = TEXT("AngleHiddenWindow"); + static const TCHAR className[] = TEXT("STATIC"); + + { + 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; + + static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED"); + if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1")) + behaviorFlags |= D3DCREATE_MULTITHREADED; + + { + 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)) + { + 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) + { + result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**)&mDeviceEx); + ASSERT(SUCCEEDED(result)); + } + + { + 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(); + + 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 + } + + const gl::Caps &rendererCaps = getRendererCaps(); + + mForceSetVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); + mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); + + mForceSetPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); + mCurPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); + + mCurVertexTextureSerials.resize(rendererCaps.maxVertexTextureImageUnits); + mCurPixelTextureSerials.resize(rendererCaps.maxTextureImageUnits); + + 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++) + { + const d3d9::D3DFormat &renderTargetFormatInfo = d3d9::GetD3DFormatInfo(RenderTargetFormats[formatIndex]); + const gl::TextureCaps &renderTargetFormatCaps = getRendererTextureCaps().get(renderTargetFormatInfo.internalFormat); + if (renderTargetFormatCaps.renderable) + { + for (unsigned int depthStencilIndex = 0; depthStencilIndex < numDepthFormats; depthStencilIndex++) + { + const d3d9::D3DFormat &depthStencilFormatInfo = d3d9::GetD3DFormatInfo(DepthStencilFormats[depthStencilIndex]); + const gl::TextureCaps &depthStencilFormatCaps = getRendererTextureCaps().get(depthStencilFormatInfo.internalFormat); + if (depthStencilFormatCaps.renderable || DepthStencilFormats[depthStencilIndex] == D3DFMT_UNKNOWN) + { + ConfigDesc newConfig; + newConfig.renderTargetFormat = renderTargetFormatInfo.internalFormat; + newConfig.depthStencilFormat = depthStencilFormatInfo.internalFormat; + newConfig.multiSample = 0; // FIXME: enumerate multi-sampling + newConfig.fastConfig = (currentDisplayMode.Format == RenderTargetFormats[formatIndex]); + 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); +} + +TransformFeedbackImpl* Renderer9::createTransformFeedback() +{ + return new TransformFeedbackD3D(); +} + +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; +} + +gl::Error Renderer9::generateSwizzle(gl::Texture *texture) +{ + // Swizzled textures are not available in ES2 or D3D9 + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &samplerState) +{ + std::vector<bool> &forceSetSamplers = (type == gl::SAMPLER_PIXEL) ? mForceSetPixelSamplerStates : mForceSetVertexSamplerStates; + std::vector<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; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *texture) +{ + int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; + int d3dSampler = index + d3dSamplerOffset; + IDirect3DBaseTexture9 *d3dTexture = NULL; + unsigned int serial = 0; + bool forceSetTexture = false; + + std::vector<unsigned int> &appliedSerials = (type == gl::SAMPLER_PIXEL) ? mCurPixelTextureSerials : mCurVertexTextureSerials; + + if (texture) + { + TextureD3D* textureImpl = TextureD3D::makeTextureD3D(texture->getImplementation()); + + TextureStorage *texStorage = textureImpl->getNativeTexture(); + if (texStorage) + { + TextureStorage9 *storage9 = TextureStorage9::makeTextureStorage9(texStorage); + 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 = textureImpl->hasDirtyImages(); + textureImpl->resetDirty(); + } + + if (forceSetTexture || appliedSerials[index] != serial) + { + mDevice->SetTexture(d3dSampler, d3dTexture); + } + + appliedSerials[index] = serial; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::setUniformBuffers(const gl::Buffer* /*vertexUniformBuffers*/[], const gl::Buffer* /*fragmentUniformBuffers*/[]) +{ + // No effect in ES2/D3D9 + return gl::Error(GL_NO_ERROR); +} + +gl::Error 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; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error 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 + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + DWORD colorMask = gl_d3d9::ConvertColorMask(formatInfo.redBits > 0 && blendState.colorMaskRed, + formatInfo.greenBits > 0 && blendState.colorMaskGreen, + formatInfo.blueBits > 0 && blendState.colorMaskBlue, + formatInfo.alphaBits > 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; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error 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; + + return gl::Error(GL_NO_ERROR); +} + +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; +} + +void 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; + + 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; +} + +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(GL_NONE, 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; +} + +gl::Error 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) + { + return gl::Error(GL_OUT_OF_MEMORY, "Unable to locate renderbuffer for FBO."); + } + + bool renderTargetChanged = false; + unsigned int renderTargetSerial = GetAttachmentSerial(attachment); + if (renderTargetSerial != mAppliedRenderTargetSerial) + { + // Apply the render target on the device + IDirect3DSurface9 *renderTargetSurface = NULL; + + RenderTarget9 *renderTarget = d3d9::GetAttachmentRenderTarget(attachment); + if (renderTarget) + { + renderTargetSurface = renderTarget->getSurface(); + } + + if (!renderTargetSurface) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal render target pointer unexpectedly null."); + } + + 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 = GetAttachmentSerial(depthStencil); + } + else if (framebuffer->getStencilbuffer()) + { + depthStencil = framebuffer->getStencilbuffer(); + stencilbufferSerial = GetAttachmentSerial(depthStencil); + } + + 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; + rx::RenderTarget9 *depthStencilRenderTarget = d3d9::GetAttachmentRenderTarget(depthStencil); + + if (depthStencilRenderTarget) + { + depthStencilSurface = depthStencilRenderTarget->getSurface(); + } + + if (!depthStencilSurface) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal depth stencil pointer unexpectedly null."); + } + + 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 gl::Error(GL_NO_ERROR); +} + +gl::Error 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]; + gl::Error error = mVertexDataManager->prepareVertexData(vertexAttributes, currentValues, programBinary, first, count, attributes, instances); + if (error.isError()) + { + return error; + } + + return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, programBinary, instances, &mRepeatDraw); +} + +// Applies the indices and element array bindings to the Direct3D 9 device +gl::Error Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) +{ + gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo); + if (error.isError()) + { + return error; + } + + // Directly binding the storage buffer is not supported for d3d9 + ASSERT(indexInfo->storage == NULL); + + if (indexInfo->serial != mAppliedIBSerial) + { + IndexBuffer9* indexBuffer = IndexBuffer9::makeIndexBuffer9(indexInfo->indexBuffer); + + mDevice->SetIndices(indexBuffer->getBuffer()); + mAppliedIBSerial = indexInfo->serial; + } + + return gl::Error(GL_NO_ERROR); +} + +void Renderer9::applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]) +{ + UNREACHABLE(); +} + +gl::Error Renderer9::drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) +{ + ASSERT(!transformFeedbackActive); + + startScene(); + + if (mode == GL_LINE_LOOP) + { + return drawLineLoop(count, GL_NONE, NULL, 0, NULL); + } + else if (instances > 0) + { + StaticIndexBufferInterface *countingIB = NULL; + gl::Error error = getCountingIB(count, &countingIB); + if (error.isError()) + { + return error; + } + + if (mAppliedIBSerial != countingIB->getSerial()) + { + IndexBuffer9 *indexBuffer = 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); + } + + return gl::Error(GL_NO_ERROR); + } + else // Regular case + { + mDevice->DrawPrimitive(mPrimitiveType, 0, mPrimitiveCount); + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error Renderer9::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei /*instances*/) +{ + startScene(); + + int minIndex = static_cast<int>(indexInfo.indexRange.start); + + if (mode == GL_POINTS) + { + return drawIndexedPoints(count, type, indices, minIndex, elementArrayBuffer); + } + else if (mode == GL_LINE_LOOP) + { + return drawLineLoop(count, type, indices, minIndex, elementArrayBuffer); + } + else + { + for (int i = 0; i < mRepeatDraw; i++) + { + GLsizei vertexCount = static_cast<int>(indexInfo.indexRange.length()) + 1; + mDevice->DrawIndexedPrimitive(mPrimitiveType, -minIndex, minIndex, vertexCount, indexInfo.startIndex, mPrimitiveCount); + } + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) +{ + // Get the raw indices for an indexed draw + if (type != GL_NONE && elementArrayBuffer) + { + 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); + gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); + if (error.isError()) + { + SafeDelete(mLineLoopIB); + return error; + } + } + + // Checked by Renderer9::applyPrimitiveType + ASSERT(count >= 0); + + if (static_cast<unsigned int>(count) + 1 > (std::numeric_limits<unsigned int>::max() / sizeof(unsigned int))) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); + } + + const unsigned int spaceNeeded = (static_cast<unsigned int>(count)+1) * sizeof(unsigned int); + gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); + if (error.isError()) + { + return error; + } + + void* mappedMemory = NULL; + unsigned int offset = 0; + error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); + if (error.isError()) + { + return error; + } + + startIndex = static_cast<unsigned int>(offset) / 4; + unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory); + + switch (type) + { + case GL_NONE: // Non-indexed draw + for (int i = 0; i < count; i++) + { + data[i] = i; + } + data[count] = 0; + break; + case GL_UNSIGNED_BYTE: + for (int i = 0; i < count; i++) + { + data[i] = static_cast<const GLubyte*>(indices)[i]; + } + data[count] = static_cast<const GLubyte*>(indices)[0]; + break; + case GL_UNSIGNED_SHORT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast<const GLushort*>(indices)[i]; + } + data[count] = static_cast<const GLushort*>(indices)[0]; + break; + case GL_UNSIGNED_INT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast<const GLuint*>(indices)[i]; + } + data[count] = static_cast<const GLuint*>(indices)[0]; + break; + default: UNREACHABLE(); + } + + error = mLineLoopIB->unmapBuffer(); + if (error.isError()) + { + return error; + } + } + else + { + if (!mLineLoopIB) + { + mLineLoopIB = new StreamingIndexBufferInterface(this); + gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT); + if (error.isError()) + { + SafeDelete(mLineLoopIB); + return error; + } + } + + // Checked by Renderer9::applyPrimitiveType + ASSERT(count >= 0); + + if (static_cast<unsigned int>(count) + 1 > (std::numeric_limits<unsigned short>::max() / sizeof(unsigned short))) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 16-bit looping index buffer for GL_LINE_LOOP, too many indices required."); + } + + const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * sizeof(unsigned short); + gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT); + if (error.isError()) + { + return error; + } + + void* mappedMemory = NULL; + unsigned int offset; + error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); + if (error.isError()) + { + return error; + } + + startIndex = static_cast<unsigned int>(offset) / 2; + unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory); + + switch (type) + { + case GL_NONE: // Non-indexed draw + for (int i = 0; i < count; i++) + { + data[i] = i; + } + data[count] = 0; + break; + case GL_UNSIGNED_BYTE: + for (int i = 0; i < count; i++) + { + data[i] = static_cast<const GLubyte*>(indices)[i]; + } + data[count] = static_cast<const GLubyte*>(indices)[0]; + break; + case GL_UNSIGNED_SHORT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast<const GLushort*>(indices)[i]; + } + data[count] = static_cast<const GLushort*>(indices)[0]; + break; + case GL_UNSIGNED_INT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast<const GLuint*>(indices)[i]; + } + data[count] = static_cast<const GLuint*>(indices)[0]; + break; + default: UNREACHABLE(); + } + + error = mLineLoopIB->unmapBuffer(); + if (error.isError()) + { + return error; + } + } + + 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); + + return gl::Error(GL_NO_ERROR); +} + +template <typename T> +static gl::Error drawPoints(IDirect3DDevice9* device, GLsizei count, const GLvoid *indices, int minIndex) +{ + for (int i = 0; i < count; i++) + { + unsigned int indexValue = static_cast<unsigned int>(static_cast<const T*>(indices)[i]) - minIndex; + device->DrawPrimitive(D3DPT_POINTLIST, indexValue, 1); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) +{ + // Drawing index point lists is unsupported in d3d9, fall back to a regular DrawPrimitive call + // for each individual point. This call is not expected to happen often. + + if (elementArrayBuffer) + { + 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: return drawPoints<GLubyte>(mDevice, count, indices, minIndex); + case GL_UNSIGNED_SHORT: return drawPoints<GLushort>(mDevice, count, indices, minIndex); + case GL_UNSIGNED_INT: return drawPoints<GLuint>(mDevice, count, indices, minIndex); + default: UNREACHABLE(); return gl::Error(GL_INVALID_OPERATION); + } +} + +gl::Error Renderer9::getCountingIB(size_t count, StaticIndexBufferInterface **outIB) +{ + // Update the counting index buffer if it is not large enough or has not been created yet. + if (count <= 65536) // 16-bit indices + { + const unsigned int spaceNeeded = count * sizeof(unsigned short); + + if (!mCountingIB || mCountingIB->getBufferSize() < spaceNeeded) + { + SafeDelete(mCountingIB); + mCountingIB = new StaticIndexBufferInterface(this); + mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT); + + void *mappedMemory = NULL; + gl::Error error = mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, NULL); + if (error.isError()) + { + return error; + } + + unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory); + for (size_t i = 0; i < count; i++) + { + data[i] = i; + } + + error = mCountingIB->unmapBuffer(); + if (error.isError()) + { + return error; + } + } + } + else if (getRendererExtensions().elementIndexUint) + { + const unsigned int spaceNeeded = count * sizeof(unsigned int); + + if (!mCountingIB || mCountingIB->getBufferSize() < spaceNeeded) + { + SafeDelete(mCountingIB); + mCountingIB = new StaticIndexBufferInterface(this); + mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); + + void *mappedMemory = NULL; + gl::Error error = mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, NULL); + if (error.isError()) + { + return error; + } + + unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory); + for (size_t i = 0; i < count; i++) + { + data[i] = i; + } + + error = mCountingIB->unmapBuffer(); + if (error.isError()) + { + return error; + } + } + } + else + { + return gl::Error(GL_OUT_OF_MEMORY, "Could not create a counting index buffer for glDrawArraysInstanced."); + } + + *outIB = mCountingIB; + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::applyShaders(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; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error 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; + } + + return gl::Error(GL_NO_ERROR); +} + +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); +} + +gl::Error 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 gl::Error(GL_INVALID_OPERATION); + } + + bool clearColor = clearParams.clearColor[0]; + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + if (clearParams.clearColor[i] != clearColor) + { + // Clearing individual buffers other than buffer zero is not supported by Renderer9 and ES 2.0 + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } + } + + float depth = gl::clamp01(clearParams.depthClearValue); + DWORD stencil = clearParams.stencilClearValue & 0x000000FF; + + unsigned int stencilUnmasked = 0x0; + if (clearParams.clearStencil && frameBuffer->hasStencil()) + { + unsigned int stencilSize = gl::GetInternalFormatInfo((frameBuffer->getStencilbuffer()->getActualFormat())).stencilBits; + 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) + { + const gl::FramebufferAttachment *attachment = frameBuffer->getFirstColorbuffer(); + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(attachment->getInternalFormat()); + const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(attachment->getActualFormat()); + + color = D3DCOLOR_ARGB(gl::unorm<8>((formatInfo.alphaBits == 0 && actualFormatInfo.alphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha), + gl::unorm<8>((formatInfo.redBits == 0 && actualFormatInfo.redBits > 0) ? 0.0f : clearParams.colorFClearValue.red), + gl::unorm<8>((formatInfo.greenBits == 0 && actualFormatInfo.greenBits > 0) ? 0.0f : clearParams.colorFClearValue.green), + gl::unorm<8>((formatInfo.blueBits == 0 && actualFormatInfo.blueBits > 0) ? 0.0f : clearParams.colorFClearValue.blue)); + + if ((formatInfo.redBits > 0 && !clearParams.colorMaskRed) || + (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) || + (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) || + (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha)) + { + needMaskedColorClear = true; + } + } + + if (needMaskedColorClear || needMaskedStencilClear) + { + // State which is altered in all paths from this point to the clear call is saved. + // State which is altered in only some paths will be flagged dirty in the case that + // that path is taken. + HRESULT hr; + if (mMaskedClearSavedState == NULL) + { + hr = mDevice->BeginStateBlock(); + ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); + mDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); + mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + mDevice->SetPixelShader(NULL); + mDevice->SetVertexShader(NULL); + mDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); + mDevice->SetStreamSource(0, NULL, 0, 0); + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR); + mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color); + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); + + for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mDevice->SetStreamSourceFreq(i, 1); + } + + hr = mDevice->EndStateBlock(&mMaskedClearSavedState); + ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + } + + ASSERT(mMaskedClearSavedState != NULL); + + if (mMaskedClearSavedState != NULL) + { + hr = mMaskedClearSavedState->Capture(); + ASSERT(SUCCEEDED(hr)); + } + + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); + mDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + + if (clearColor) + { + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, + gl_d3d9::ConvertColorMask(clearParams.colorMaskRed, + clearParams.colorMaskGreen, + clearParams.colorMaskBlue, + clearParams.colorMaskAlpha)); + } + else + { + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); + } + + if (stencilUnmasked != 0x0 && clearParams.clearStencil) + { + mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE); + mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE); + mDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + mDevice->SetRenderState(D3DRS_STENCILREF, stencil); + mDevice->SetRenderState(D3DRS_STENCILWRITEMASK, clearParams.stencilWriteMask); + mDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE); + mDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE); + mDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + } + else + { + mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + } + + mDevice->SetPixelShader(NULL); + mDevice->SetVertexShader(NULL); + mDevice->SetFVF(D3DFVF_XYZRHW); + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR); + mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color); + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); + + for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mDevice->SetStreamSourceFreq(i, 1); + } + + 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); + } + + return gl::Error(GL_NO_ERROR); +} + +void Renderer9::markAllStateDirty() +{ + mAppliedRenderTargetSerial = 0; + mAppliedDepthbufferSerial = 0; + mAppliedStencilbufferSerial = 0; + mDepthStencilInitialized = false; + mRenderTargetDescInitialized = false; + + mForceSetDepthStencilState = true; + mForceSetRasterState = true; + mForceSetScissor = true; + mForceSetViewport = true; + mForceSetBlendState = true; + + ASSERT(mForceSetVertexSamplerStates.size() == mCurVertexTextureSerials.size()); + for (unsigned int i = 0; i < mForceSetVertexSamplerStates.size(); i++) + { + mForceSetVertexSamplerStates[i] = true; + mCurVertexTextureSerials[i] = 0; + } + + ASSERT(mForceSetPixelSamplerStates.size() == mCurPixelTextureSerials.size()); + for (unsigned int i = 0; i < mForceSetPixelSamplerStates.size(); 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); + SafeDelete(mCountingIB); + + 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; +} + +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::getReservedVertexUniformBuffers() const +{ + return 0; +} + +unsigned int Renderer9::getReservedFragmentUniformBuffers() const +{ + return 0; +} + +bool Renderer9::getShareHandleSupport() const +{ + // PIX doesn't seem to support using share handles, so disable them. + return (mD3d9Ex != NULL) && !gl::perfActive(); +} + +bool Renderer9::getPostSubBufferSupport() const +{ + return true; +} + +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; +} + +bool Renderer9::copyToRenderTarget2D(TextureStorage *dest, TextureStorage *source) +{ + bool result = false; + + if (source && dest) + { + TextureStorage9_2D *source9 = TextureStorage9_2D::makeTextureStorage9_2D(source); + TextureStorage9_2D *dest9 = TextureStorage9_2D::makeTextureStorage9_2D(dest); + + 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::copyToRenderTargetCube(TextureStorage *dest, TextureStorage *source) +{ + bool result = false; + + if (source && dest) + { + TextureStorage9_Cube *source9 = TextureStorage9_Cube::makeTextureStorage9_Cube(source); + TextureStorage9_Cube *dest9 = TextureStorage9_Cube::makeTextureStorage9_Cube(dest); + 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::copyToRenderTarget3D(TextureStorage *dest, TextureStorage *source) +{ + // 3D textures are not available in the D3D9 backend. + UNREACHABLE(); + return false; +} + +bool Renderer9::copyToRenderTarget2DArray(TextureStorage *dest, TextureStorage *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::copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level) +{ + RECT rect; + rect.left = sourceRect.x; + rect.top = sourceRect.y; + rect.right = sourceRect.x + sourceRect.width; + rect.bottom = sourceRect.y + sourceRect.height; + + return mBlit->copy2D(framebuffer, rect, destFormat, xoffset, yoffset, storage, level); +} + +bool Renderer9::copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level) +{ + RECT rect; + rect.left = sourceRect.x; + rect.top = sourceRect.y; + rect.right = sourceRect.x + sourceRect.width; + rect.bottom = sourceRect.y + sourceRect.height; + + return mBlit->copyCube(framebuffer, rect, destFormat, xoffset, yoffset, storage, target, level); +} + +bool Renderer9::copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) +{ + // 3D textures are not available in the D3D9 backend. + UNREACHABLE(); + return false; +} + +bool Renderer9::copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *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 = d3d9::GetAttachmentRenderTarget(readBuffer); + } + if (drawBuffer) + { + drawRenderTarget = d3d9::GetAttachmentRenderTarget(drawBuffer); + } + + 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 = d3d9::GetAttachmentRenderTarget(readBuffer); + } + if (drawBuffer) + { + drawDepthStencil = d3d9::GetAttachmentRenderTarget(drawBuffer); + } + + 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; +} + +gl::Error Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) +{ + ASSERT(pack.pixelBuffer.get() == NULL); + + RenderTarget9 *renderTarget = NULL; + IDirect3DSurface9 *surface = NULL; + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); + + if (colorbuffer) + { + renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer); + } + + if (renderTarget) + { + surface = renderTarget->getSurface(); + } + + if (!surface) + { + // context must be lost + return gl::Error(GL_NO_ERROR); + } + + D3DSURFACE_DESC desc; + surface->GetDesc(&desc); + + if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) + { + UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target + SafeRelease(surface); + return gl::Error(GL_OUT_OF_MEMORY, "ReadPixels is unimplemented for multisampled framebuffer attachments."); + } + + 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, reinterpret_cast<void**>(&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, "Failed to allocate internal texture for ReadPixels."); + } + } + + 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(); + } + else + { + UNREACHABLE(); + } + + return gl::Error(GL_OUT_OF_MEMORY, "Failed to read internal render target data."); + } + + if (directToPixels) + { + SafeRelease(systemSurface); + return gl::Error(GL_NO_ERROR); + } + + RECT rect; + rect.left = gl::clamp(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 gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal render target."); + } + + uint8_t *source; + int inputPitch; + if (pack.reverseRowOrder) + { + source = reinterpret_cast<uint8_t*>(lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1); + inputPitch = -lock.Pitch; + } + else + { + source = reinterpret_cast<uint8_t*>(lock.pBits); + inputPitch = lock.Pitch; + } + + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); + const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(d3dFormatInfo.internalFormat); + if (sourceFormatInfo.format == format && sourceFormatInfo.type == type) + { + // Direct copy possible + for (int y = 0; y < rect.bottom - rect.top; y++) + { + memcpy(pixels + y * outputPitch, source + y * inputPitch, (rect.right - rect.left) * sourceFormatInfo.pixelBytes); + } + } + else + { + const d3d9::D3DFormat &sourceD3DFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); + ColorCopyFunction fastCopyFunc = sourceD3DFormatInfo.getFastCopyFunction(format, type); + + const gl::FormatType &destFormatTypeInfo = gl::GetFormatTypeInfo(format, type); + const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(destFormatTypeInfo.internalFormat); + + 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++) + { + uint8_t *dest = pixels + y * outputPitch + x * destFormatInfo.pixelBytes; + const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; + + fastCopyFunc(src, dest); + } + } + } + else + { + uint8_t temp[sizeof(gl::ColorF)]; + for (int y = 0; y < rect.bottom - rect.top; y++) + { + for (int x = 0; x < rect.right - rect.left; x++) + { + uint8_t *dest = pixels + y * outputPitch + x * destFormatInfo.pixelBytes; + const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; + + // readFunc and writeFunc will be using the same type of color, CopyTexImage + // will not allow the copy otherwise. + sourceD3DFormatInfo.colorReadFunction(src, temp); + destFormatTypeInfo.colorWriteFunction(temp, dest); + } + } + } + } + + systemSurface->UnlockRect(); + SafeRelease(systemSurface); + + return gl::Error(GL_NO_ERROR); +} + +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; +} + +ShaderImpl *Renderer9::createShader(GLenum type) +{ + return new ShaderD3D(type, this); +} + +ProgramImpl *Renderer9::createProgram() +{ + return new ProgramD3D(this); +} + +void Renderer9::releaseShaderCompiler() +{ + ShaderD3D::releaseCompiler(); +} + +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; +} + +TextureImpl *Renderer9::createTexture(GLenum target) +{ + switch(target) + { + case GL_TEXTURE_2D: return new TextureD3D_2D(this); + case GL_TEXTURE_CUBE_MAP: return new TextureD3D_Cube(this); + default: UNREACHABLE(); + } + + return NULL; +} + +bool Renderer9::getLUID(LUID *adapterLuid) const +{ + adapterLuid->HighPart = 0; + adapterLuid->LowPart = 0; + + if (mD3d9Ex) + { + mD3d9Ex->GetAdapterLUID(mAdapter, adapterLuid); + return true; + } + + return false; +} + +rx::VertexConversionType Renderer9::getVertexConversionType(const gl::VertexFormat &vertexFormat) const +{ + return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormat).conversionType; +} + +GLenum Renderer9::getVertexComponentType(const gl::VertexFormat &vertexFormat) const +{ + return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormat).componentType; +} + +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..dd5f30268a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h @@ -0,0 +1,342 @@ +// +// 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; +class StaticIndexBufferInterface; +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 gl::Error generateSwizzle(gl::Texture *texture); + virtual gl::Error setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler); + virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture); + + virtual gl::Error setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]); + + virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState); + virtual gl::Error setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask); + virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, + int stencilBackRef, bool frontFaceCCW); + + virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled); + virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, + bool ignoreViewport); + + virtual gl::Error applyRenderTarget(gl::Framebuffer *frameBuffer); + virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive); + virtual gl::Error applyUniforms(const gl::ProgramBinary &programBinary); + virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount); + virtual gl::Error applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], + GLint first, GLsizei count, GLsizei instances); + virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); + + virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]); + + virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive); + virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); + + virtual gl::Error 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 getReservedVertexUniformVectors() const; + virtual unsigned int getReservedFragmentUniformVectors() const; + virtual unsigned int getReservedVertexUniformBuffers() const; + virtual unsigned int getReservedFragmentUniformBuffers() const; + virtual bool getShareHandleSupport() const; + virtual bool getPostSubBufferSupport() const; + + virtual int getMajorShaderModel() const; + DWORD getCapsDeclTypes() const; + virtual int getMinSwapInterval() const; + virtual int getMaxSwapInterval() const; + + // Pixel operations + virtual bool copyToRenderTarget2D(TextureStorage *dest, TextureStorage *source); + virtual bool copyToRenderTargetCube(TextureStorage *dest, TextureStorage *source); + virtual bool copyToRenderTarget3D(TextureStorage *dest, TextureStorage *source); + virtual bool copyToRenderTarget2DArray(TextureStorage *dest, TextureStorage *source); + + virtual bool copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level); + virtual bool copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level); + virtual bool copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level); + virtual bool copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *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 gl::Error readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels); + + // RenderTarget creation + virtual RenderTarget *createRenderTarget(SwapChain *swapChain, bool depth); + virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples); + + // Shader creation + virtual ShaderImpl *createShader(GLenum type); + virtual ProgramImpl *createProgram(); + + // Shader operations + virtual void releaseShaderCompiler(); + 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 TextureImpl *createTexture(GLenum target); + + // 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(); + + // Transform Feedback creation + virtual TransformFeedbackImpl* createTransformFeedback(); + + // 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 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); + + gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); + gl::Error drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); + + gl::Error getCountingIB(size_t count, StaticIndexBufferInterface **outIB); + + 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; + + // 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 + std::vector<bool> mForceSetVertexSamplerStates; + std::vector<gl::SamplerState> mCurVertexSamplerStates; + + std::vector<bool> mForceSetPixelSamplerStates; + std::vector<gl::SamplerState> mCurPixelSamplerStates; + + // Currently applied textures + std::vector<unsigned int> mCurVertexTextureSerials; + std::vector<unsigned int> mCurPixelTextureSerials; + + 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; + StaticIndexBufferInterface *mCountingIB; + + enum { NUM_NULL_COLORBUFFER_CACHE_ENTRIES = 12 }; + struct NullColorbufferCacheEntry + { + UINT lruCount; + int width; + int height; + gl::FramebufferAttachment *buffer; + } mNullColorbufferCache[NUM_NULL_COLORBUFFER_CACHE_ENTRIES]; + UINT mMaxNullColorbufferLRU; + +}; + +} +#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..2ad3022839 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h @@ -0,0 +1,106 @@ +// +// 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" + +#include <cstddef> +#include <unordered_map> +#include <string> + +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..bc7120461b --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.cpp @@ -0,0 +1,53 @@ +// +// 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..0aeaabb1ca --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp @@ -0,0 +1,418 @@ +// +// 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) +{ +#ifdef 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; + } + + const d3d9::TextureFormat &backBufferd3dFormatInfo = d3d9::GetTextureFormatInfo(mBackBufferFormat); + result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET, + backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT, &mOffscreenTexture, + pShareHandle); + if (FAILED(result)) + { + ERR("Could not create offscreen texture: %08lX", result); + release(); + + if (d3d9::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + + IDirect3DSurface9 *oldRenderTarget = mRenderTarget; + + result = mOffscreenTexture->GetSurfaceLevel(0, &mRenderTarget); + ASSERT(SUCCEEDED(result)); + + if (oldRenderTarget) + { + RECT rect = + { + 0, 0, + mWidth, mHeight + }; + + if (rect.right > static_cast<LONG>(backbufferWidth)) + { + rect.right = backbufferWidth; + } + + if (rect.bottom > static_cast<LONG>(backbufferHeight)) + { + rect.bottom = backbufferHeight; + } + + mRenderer->endScene(); + + result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE); + ASSERT(SUCCEEDED(result)); + + SafeRelease(oldRenderTarget); + } + + const d3d9::TextureFormat &depthBufferd3dFormatInfo = d3d9::GetTextureFormatInfo(mDepthBufferFormat); + + if (mWindow) + { + D3DPRESENT_PARAMETERS presentParameters = {0}; + presentParameters.AutoDepthStencilFormat = depthBufferd3dFormatInfo.renderFormat; + presentParameters.BackBufferCount = 1; + presentParameters.BackBufferFormat = backBufferd3dFormatInfo.renderFormat; + 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, + depthBufferd3dFormatInfo.renderFormat, + D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL); + + ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result); + release(); + + if (d3d9::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + } + + mWidth = backbufferWidth; + mHeight = backbufferHeight; + mSwapInterval = swapInterval; + + return EGL_SUCCESS; +} + +// parameters should be validated/clamped by caller +EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height, 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..f44e33db18 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp @@ -0,0 +1,323 @@ +// +// 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/renderer/d3d/d3d9/TextureStorage9.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.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/renderer/d3d/TextureD3D.h" +#include "libGLESv2/Texture.h" +#include "libGLESv2/main.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; + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + d3dusage |= D3DUSAGE_DEPTHSTENCIL; + } + else if (renderTarget && (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN)) + { + d3dusage |= D3DUSAGE_RENDERTARGET; + } + + return d3dusage; +} + + +bool TextureStorage9::isRenderTarget() const +{ + return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0; +} + +bool TextureStorage9::isManaged() const +{ + return (mD3DPool == D3DPOOL_MANAGED); +} + +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(); + initializeSerials(1, 1); +} + +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(); + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); + d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &width, &height, &mTopLevel); + UINT creationLevels = (levels == 0) ? 0 : mTopLevel + levels; + + HRESULT result = device->CreateTexture(width, height, creationLevels, getUsage(), d3dFormatInfo.texFormat, getPool(), &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + gl::error(GL_OUT_OF_MEMORY); + } + } + + initializeRenderTarget(); + initializeSerials(getLevelCount(), 1); +} + +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(const gl::ImageIndex &/*index*/) +{ + return mRenderTarget; +} + +void TextureStorage9_2D::generateMipmaps() +{ + // Base level must already be defined + + for (int level = 1; level < getLevelCount(); 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; + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); + d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &size, &height, &mTopLevel); + UINT creationLevels = (levels == 0) ? 0 : mTopLevel + levels; + + HRESULT result = device->CreateCubeTexture(size, creationLevels, getUsage(), d3dFormatInfo.texFormat, getPool(), &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + gl::error(GL_OUT_OF_MEMORY); + } + } + + initializeRenderTarget(); + initializeSerials(getLevelCount() * 6, 6); +} + +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::getRenderTarget(const gl::ImageIndex &index) +{ + return mRenderTarget[index.layerIndex]; +} + +void TextureStorage9_Cube::generateMipmaps() +{ + // Base level must already be defined + + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + for (int level = 1; level < getLevelCount(); 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..e698c7dd56 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h @@ -0,0 +1,106 @@ +// +// 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(const gl::ImageIndex &index) = 0; + virtual void generateMipmaps() = 0; + + 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(const gl::ImageIndex &index); + virtual IDirect3DBaseTexture9 *getBaseTexture() const; + virtual void generateMipmaps(); + + 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 *getRenderTarget(const gl::ImageIndex &index); + virtual IDirect3DBaseTexture9 *getBaseTexture() const; + virtual void generateMipmaps(); + + 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..4cf7779118 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp @@ -0,0 +1,233 @@ +// +// 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/d3d/d3d9/Renderer9.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/renderer/vertexconversion.h" +#include "libGLESv2/renderer/BufferImpl.h" +#include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/Buffer.h" + +namespace rx +{ + +VertexBuffer9::VertexBuffer9(rx::Renderer9 *renderer) : mRenderer(renderer) +{ + mVertexBuffer = NULL; + mBufferSize = 0; + mDynamicUsage = false; +} + +VertexBuffer9::~VertexBuffer9() +{ + SafeRelease(mVertexBuffer); +} + +gl::Error VertexBuffer9::initialize(unsigned int size, bool dynamicUsage) +{ + SafeRelease(mVertexBuffer); + + updateSerial(); + + if (size > 0) + { + DWORD flags = D3DUSAGE_WRITEONLY; + if (dynamicUsage) + { + flags |= D3DUSAGE_DYNAMIC; + } + + HRESULT result = mRenderer->createVertexBuffer(size, flags, &mVertexBuffer); + + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size); + } + } + + mBufferSize = size; + mDynamicUsage = dynamicUsage; + return gl::Error(GL_NO_ERROR); +} + +VertexBuffer9 *VertexBuffer9::makeVertexBuffer9(VertexBuffer *vertexBuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer9*, vertexBuffer)); + return static_cast<VertexBuffer9*>(vertexBuffer); +} + +gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset) +{ + if (!mVertexBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + } + + gl::Buffer *buffer = attrib.buffer.get(); + + int inputStride = gl::ComputeVertexAttributeStride(attrib); + int elementSize = gl::ComputeVertexAttributeTypeSize(attrib); + + DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0; + + uint8_t *mapPtr = NULL; + + unsigned int mapSize; + gl::Error error = spaceRequired(attrib, count, instances, &mapSize); + if (error.isError()) + { + return error; + } + + HRESULT result = mVertexBuffer->Lock(offset, mapSize, reinterpret_cast<void**>(&mapPtr), lockFlags); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal vertex buffer, HRESULT: 0x%08x.", result); + } + + const uint8_t *input = NULL; + if (attrib.enabled) + { + if (buffer) + { + BufferImpl *storage = buffer->getImplementation(); + input = static_cast<const uint8_t*>(storage->getData()) + static_cast<int>(attrib.offset); + } + else + { + input = static_cast<const uint8_t*>(attrib.pointer); + } + } + else + { + input = reinterpret_cast<const uint8_t*>(currentValue.FloatValues); + } + + if (instances == 0 || attrib.divisor == 0) + { + input += inputStride * start; + } + + gl::VertexFormat vertexFormat(attrib, currentValue.Type); + const d3d9::VertexFormat &d3dVertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormat); + bool needsConversion = (d3dVertexInfo.conversionType & VERTEX_CONVERT_CPU) > 0; + + if (!needsConversion && inputStride == elementSize) + { + size_t copySize = static_cast<size_t>(count) * static_cast<size_t>(inputStride); + memcpy(mapPtr, input, copySize); + } + else + { + d3dVertexInfo.copyFunction(input, inputStride, count, mapPtr); + } + + mVertexBuffer->Unlock(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error 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; +} + +gl::Error VertexBuffer9::setBufferSize(unsigned int size) +{ + if (size > mBufferSize) + { + return initialize(size, mDynamicUsage); + } + else + { + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error VertexBuffer9::discard() +{ + if (!mVertexBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + } + + void *dummy; + HRESULT result; + + result = mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal buffer for discarding, HRESULT: 0x%08x", result); + } + + result = mVertexBuffer->Unlock(); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal buffer for discarding, HRESULT: 0x%08x", result); + } + + return gl::Error(GL_NO_ERROR); +} + +IDirect3DVertexBuffer9 * VertexBuffer9::getBuffer() const +{ + return mVertexBuffer; +} + +gl::Error VertexBuffer9::spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, + unsigned int *outSpaceRequired) const +{ + gl::VertexFormat vertexFormat(attrib, GL_FLOAT); + const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormat); + + if (attrib.enabled) + { + unsigned int elementCount = 0; + if (instances == 0 || attrib.divisor == 0) + { + elementCount = count; + } + else + { + // Round up to divisor, if possible + elementCount = rx::UnsignedCeilDivide(static_cast<unsigned int>(instances), attrib.divisor); + } + + if (d3d9VertexInfo.outputElementSize <= std::numeric_limits<unsigned int>::max() / elementCount) + { + if (outSpaceRequired) + { + *outSpaceRequired = d3d9VertexInfo.outputElementSize * elementCount; + } + return gl::Error(GL_NO_ERROR); + } + else + { + return gl::Error(GL_OUT_OF_MEMORY, "New vertex buffer size would result in an overflow."); + } + } + else + { + const unsigned int elementSize = 4; + if (outSpaceRequired) + { + *outSpaceRequired = elementSize * 4; + } + return gl::Error(GL_NO_ERROR); + } +} + +} 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..bdcf4bb64a --- /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 *renderer); + virtual ~VertexBuffer9(); + + virtual gl::Error initialize(unsigned int size, bool dynamicUsage); + + static VertexBuffer9 *makeVertexBuffer9(VertexBuffer *vertexBuffer); + + virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset); + + virtual gl::Error getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, unsigned int *outSpaceRequired) const; + + virtual unsigned int getBufferSize() const; + virtual gl::Error setBufferSize(unsigned int size); + virtual gl::Error discard(); + + IDirect3DVertexBuffer9 *getBuffer() const; + + private: + DISALLOW_COPY_AND_ASSIGN(VertexBuffer9); + + rx::Renderer9 *mRenderer; + + IDirect3DVertexBuffer9 *mVertexBuffer; + unsigned int mBufferSize; + bool mDynamicUsage; + + gl::Error spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, + unsigned int *outSpaceRequired) const; +}; + +} + +#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..cefd786f11 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.cpp @@ -0,0 +1,237 @@ +// +// 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/renderer/d3d/d3d9/VertexDeclarationCache.h" +#include "libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/VertexAttribute.h" + +namespace rx +{ + +VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0) +{ + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + mVertexDeclCache[i].vertexDeclaration = NULL; + mVertexDeclCache[i].lruCount = 0; + } + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mAppliedVBs[i].serial = 0; + } + + mLastSetVDecl = NULL; + mInstancingEnabled = true; +} + +VertexDeclarationCache::~VertexDeclarationCache() +{ + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + SafeRelease(mVertexDeclCache[i].vertexDeclaration); + } +} + +gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, 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) + { + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; ++i) + { + if (attributes[i].divisor != 0) + { + // If a divisor is set, it still applies even if an instanced draw was not used, so treat + // as a single-instance draw. + instances = 1; + break; + } + } + } + + if (instances > 0) + { + // Find an indexed attribute to be mapped to D3D stream 0 + for (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 + } + } + + // The validation layer checks that there is at least one active attribute with a zero divisor as per + // the GL_ANGLE_instanced_arrays spec. + ASSERT(indexedAttribute != gl::MAX_VERTEX_ATTRIBS); + } + + D3DCAPS9 caps; + device->GetDeviceCaps(&caps); + + 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); + const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(caps.DeclTypes, vertexFormat); + + element->Stream = stream; + element->Offset = 0; + element->Type = d3d9VertexInfo.nativeFormat; + 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::Error(GL_NO_ERROR); + } + } + + VertexDeclCacheEntry *lastCache = mVertexDeclCache; + + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + if (mVertexDeclCache[i].lruCount < lastCache->lruCount) + { + lastCache = &mVertexDeclCache[i]; + } + } + + if (lastCache->vertexDeclaration != NULL) + { + SafeRelease(lastCache->vertexDeclaration); + // mLastSetVDecl is set to the replacement, so we don't have to worry + // about it. + } + + memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)); + HRESULT result = device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal vertex declaration, result: 0x%X.", result); + } + + device->SetVertexDeclaration(lastCache->vertexDeclaration); + mLastSetVDecl = lastCache->vertexDeclaration; + lastCache->lruCount = ++mMaxLru; + + return gl::Error(GL_NO_ERROR); +} + +void VertexDeclarationCache::markStateDirty() +{ + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mAppliedVBs[i].serial = 0; + } + + mLastSetVDecl = NULL; + mInstancingEnabled = true; // Forces it to be disabled when not used +} + +} diff --git a/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..9af36e0d7a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h @@ -0,0 +1,59 @@ +// +// 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/Error.h" +#include "libGLESv2/renderer/d3d/VertexDataManager.h" + +namespace gl +{ +class VertexDataManager; +} + +namespace rx +{ + +class VertexDeclarationCache +{ + public: + VertexDeclarationCache(); + ~VertexDeclarationCache(); + + gl::Error 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..f3acaf7987 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp @@ -0,0 +1,588 @@ +// +// 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 +{ + +namespace d3d9 +{ + +const D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Z'))); +const D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N', 'U', 'L', 'L'))); + +struct D3D9FastCopyFormat +{ + GLenum destFormat; + GLenum destType; + ColorCopyFunction copyFunction; + + D3D9FastCopyFormat(GLenum destFormat, GLenum destType, ColorCopyFunction copyFunction) + : destFormat(destFormat), destType(destType), copyFunction(copyFunction) + { } + + bool operator<(const D3D9FastCopyFormat& other) const + { + return memcmp(this, &other, sizeof(D3D9FastCopyFormat)) < 0; + } +}; + +typedef std::multimap<D3DFORMAT, D3D9FastCopyFormat> D3D9FastCopyMap; + +static D3D9FastCopyMap BuildFastCopyMap() +{ + D3D9FastCopyMap map; + + map.insert(std::make_pair(D3DFMT_A8R8G8B8, D3D9FastCopyFormat(GL_RGBA, GL_UNSIGNED_BYTE, CopyBGRA8ToRGBA8))); + + return map; +} + +// A map to determine the pixel size and mip generation function of a given D3D format +typedef std::map<D3DFORMAT, D3DFormat> D3D9FormatInfoMap; + +D3DFormat::D3DFormat() + : pixelBytes(0), + blockWidth(0), + blockHeight(0), + internalFormat(GL_NONE), + mipGenerationFunction(NULL), + colorReadFunction(NULL), + fastCopyFunctions() +{ +} + +ColorCopyFunction D3DFormat::getFastCopyFunction(GLenum format, GLenum type) const +{ + FastCopyFunctionMap::const_iterator iter = fastCopyFunctions.find(std::make_pair(format, type)); + return (iter != fastCopyFunctions.end()) ? iter->second : NULL; +} + +static inline void InsertD3DFormatInfo(D3D9FormatInfoMap *map, D3DFORMAT format, GLuint bits, GLuint blockWidth, + GLuint blockHeight, GLenum internalFormat, MipGenerationFunction mipFunc, + ColorReadFunction colorReadFunc) +{ + D3DFormat info; + info.pixelBytes = bits / 8; + info.blockWidth = blockWidth; + info.blockHeight = blockHeight; + info.internalFormat = internalFormat; + info.mipGenerationFunction = mipFunc; + info.colorReadFunction = colorReadFunc; + + static const D3D9FastCopyMap fastCopyMap = BuildFastCopyMap(); + std::pair<D3D9FastCopyMap::const_iterator, D3D9FastCopyMap::const_iterator> fastCopyIter = fastCopyMap.equal_range(format); + for (D3D9FastCopyMap::const_iterator i = fastCopyIter.first; i != fastCopyIter.second; i++) + { + info.fastCopyFunctions.insert(std::make_pair(std::make_pair(i->second.destFormat, i->second.destType), i->second.copyFunction)); + } + + map->insert(std::make_pair(format, info)); +} + +static D3D9FormatInfoMap BuildD3D9FormatInfoMap() +{ + D3D9FormatInfoMap map; + + // | D3DFORMAT | S |W |H | Internal format | Mip generation function | Color read function | + InsertD3DFormatInfo(&map, D3DFMT_NULL, 0, 0, 0, GL_NONE, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_UNKNOWN, 0, 0, 0, GL_NONE, NULL, NULL ); + + InsertD3DFormatInfo(&map, D3DFMT_L8, 8, 1, 1, GL_LUMINANCE8_EXT, GenerateMip<L8>, ReadColor<L8, GLfloat> ); + InsertD3DFormatInfo(&map, D3DFMT_A8, 8, 1, 1, GL_ALPHA8_EXT, GenerateMip<A8>, ReadColor<A8, GLfloat> ); + InsertD3DFormatInfo(&map, D3DFMT_A8L8, 16, 1, 1, GL_LUMINANCE8_ALPHA8_EXT, GenerateMip<A8L8>, ReadColor<A8L8, GLfloat> ); + InsertD3DFormatInfo(&map, D3DFMT_A4R4G4B4, 16, 1, 1, GL_BGRA4_ANGLEX, GenerateMip<B4G4R4A4>, ReadColor<B4G4R4A4, GLfloat> ); + InsertD3DFormatInfo(&map, D3DFMT_A1R5G5B5, 16, 1, 1, GL_BGR5_A1_ANGLEX, GenerateMip<B5G5R5A1>, ReadColor<B5G5R5A1, GLfloat> ); + InsertD3DFormatInfo(&map, D3DFMT_R5G6B5, 16, 1, 1, GL_RGB565, GenerateMip<R5G6B5>, ReadColor<R5G6B5, GLfloat> ); + InsertD3DFormatInfo(&map, D3DFMT_X8R8G8B8, 32, 1, 1, GL_BGRA8_EXT, GenerateMip<B8G8R8X8>, ReadColor<B8G8R8X8, GLfloat> ); + InsertD3DFormatInfo(&map, D3DFMT_A8R8G8B8, 32, 1, 1, GL_BGRA8_EXT, GenerateMip<B8G8R8A8>, ReadColor<B8G8R8A8, GLfloat> ); + InsertD3DFormatInfo(&map, D3DFMT_R16F, 16, 1, 1, GL_R16F_EXT, GenerateMip<R16F>, ReadColor<R16F, GLfloat> ); + InsertD3DFormatInfo(&map, D3DFMT_G16R16F, 32, 1, 1, GL_RG16F_EXT, GenerateMip<R16G16F>, ReadColor<R16G16F, GLfloat> ); + InsertD3DFormatInfo(&map, D3DFMT_A16B16G16R16F, 64, 1, 1, GL_RGBA16F_EXT, GenerateMip<R16G16B16A16F>, ReadColor<R16G16B16A16F, GLfloat>); + InsertD3DFormatInfo(&map, D3DFMT_R32F, 32, 1, 1, GL_R32F_EXT, GenerateMip<R32F>, ReadColor<R32F, GLfloat> ); + InsertD3DFormatInfo(&map, D3DFMT_G32R32F, 64, 1, 1, GL_RG32F_EXT, GenerateMip<R32G32F>, ReadColor<R32G32F, GLfloat> ); + InsertD3DFormatInfo(&map, D3DFMT_A32B32G32R32F, 128, 1, 1, GL_RGBA32F_EXT, GenerateMip<R32G32B32A32F>, ReadColor<R32G32B32A32F, GLfloat>); + + InsertD3DFormatInfo(&map, D3DFMT_D16, 16, 1, 1, GL_DEPTH_COMPONENT16, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_D24S8, 32, 1, 1, GL_DEPTH24_STENCIL8_OES, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_D24X8, 32, 1, 1, GL_DEPTH_COMPONENT16, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_D32, 32, 1, 1, GL_DEPTH_COMPONENT32_OES, NULL, NULL ); + + InsertD3DFormatInfo(&map, D3DFMT_INTZ, 32, 1, 1, GL_DEPTH24_STENCIL8_OES, NULL, NULL ); + + InsertD3DFormatInfo(&map, D3DFMT_DXT1, 64, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_DXT3, 128, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_DXT5, 128, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, NULL, NULL ); + + return map; +} + +const D3DFormat &GetD3DFormatInfo(D3DFORMAT format) +{ + static const D3D9FormatInfoMap infoMap = BuildD3D9FormatInfoMap(); + D3D9FormatInfoMap::const_iterator iter = infoMap.find(format); + if (iter != infoMap.end()) + { + return iter->second; + } + else + { + static const D3DFormat defaultInfo; + return defaultInfo; + } +} + + + +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; +} + +// 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(); +} + +typedef std::pair<GLenum, TextureFormat> D3D9FormatPair; +typedef std::map<GLenum, TextureFormat> D3D9FormatMap; + +TextureFormat::TextureFormat() + : texFormat(D3DFMT_NULL), + renderFormat(D3DFMT_NULL), + dataInitializerFunction(NULL), + loadFunction(UnreachableLoad) +{ +} + +static inline void InsertD3D9FormatInfo(D3D9FormatMap *map, GLenum internalFormat, D3DFORMAT texFormat, + D3DFORMAT renderFormat, LoadImageFunction loadFunction) +{ + TextureFormat info; + info.texFormat = texFormat; + info.renderFormat = renderFormat; + + static const InternalFormatInitialzerMap dataInitializationMap = BuildInternalFormatInitialzerMap(); + InternalFormatInitialzerMap::const_iterator dataInitIter = dataInitializationMap.find(internalFormat); + info.dataInitializerFunction = (dataInitIter != dataInitializationMap.end()) ? dataInitIter->second : NULL; + + info.loadFunction = loadFunction; + + map->insert(std::make_pair(internalFormat, info)); +} + +static D3D9FormatMap BuildD3D9FormatMap() +{ + D3D9FormatMap map; + + // | Internal format | Texture format | Render format | Load function | + InsertD3D9FormatInfo(&map, GL_NONE, D3DFMT_NULL, D3DFMT_NULL, UnreachableLoad ); + + // We choose to downsample the GL_DEPTH_COMPONENT32_OES format to a 24-bit format because D3DFMT_D32 is not widely + // supported. We're allowed to do this because: + // - The ES spec 2.0.25 sec 3.7.1 states that we're allowed to store texture formats with internal format + // resolutions of our own choosing. + // - OES_depth_texture states that downsampling of the depth formats is allowed. + // - ANGLE_depth_texture does not state minimum required resolutions of the depth texture formats it + // introduces. + // In ES3 however, there are minimum resolutions for the texture formats and this would not be allowed. + + InsertD3D9FormatInfo(&map, GL_DEPTH_COMPONENT16, D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad ); + InsertD3D9FormatInfo(&map, GL_DEPTH_COMPONENT32_OES, D3DFMT_INTZ, D3DFMT_D24X8, UnreachableLoad ); + InsertD3D9FormatInfo(&map, GL_DEPTH24_STENCIL8_OES, D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad ); + InsertD3D9FormatInfo(&map, GL_STENCIL_INDEX8, D3DFMT_UNKNOWN, D3DFMT_D24S8, UnreachableLoad ); // TODO: What's the texture format? + + InsertD3D9FormatInfo(&map, GL_RGBA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative<GLfloat, 4> ); + InsertD3D9FormatInfo(&map, GL_RGB32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative3To4<GLfloat, gl::Float32One>); + InsertD3D9FormatInfo(&map, GL_RG32F_EXT, D3DFMT_G32R32F, D3DFMT_G32R32F, LoadToNative<GLfloat, 2> ); + InsertD3D9FormatInfo(&map, GL_R32F_EXT, D3DFMT_R32F, D3DFMT_R32F, LoadToNative<GLfloat, 1> ); + InsertD3D9FormatInfo(&map, GL_ALPHA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadA32FToRGBA32F ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadL32FToRGBA32F ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadLA32FToRGBA32F ); + + InsertD3D9FormatInfo(&map, GL_RGBA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative<GLhalf, 4> ); + InsertD3D9FormatInfo(&map, GL_RGB16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative3To4<GLhalf, gl::Float16One> ); + InsertD3D9FormatInfo(&map, GL_RG16F_EXT, D3DFMT_G16R16F, D3DFMT_G16R16F, LoadToNative<GLhalf, 2> ); + InsertD3D9FormatInfo(&map, GL_R16F_EXT, D3DFMT_R16F, D3DFMT_R16F, LoadToNative<GLhalf, 1> ); + InsertD3D9FormatInfo(&map, GL_ALPHA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadA16FToRGBA16F ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadL16FToRGBA16F ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadLA16FToRGBA16F ); + + InsertD3D9FormatInfo(&map, GL_ALPHA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, FallbackLoad<gl::supportsSSE2, LoadA8ToBGRA8_SSE2, LoadA8ToBGRA8>); + + InsertD3D9FormatInfo(&map, GL_RGB8_OES, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRGB8ToBGRX8 ); + InsertD3D9FormatInfo(&map, GL_RGB565, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR5G6B5ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_RGBA8_OES, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, FallbackLoad<gl::supportsSSE2, LoadRGBA8ToBGRA8_SSE2, LoadRGBA8ToBGRA8>); + InsertD3D9FormatInfo(&map, GL_RGBA4, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGBA4ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_RGB5_A1, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGB5A1ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_R8_EXT, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR8ToBGRX8 ); + InsertD3D9FormatInfo(&map, GL_RG8_EXT, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRG8ToBGRX8 ); + + InsertD3D9FormatInfo(&map, GL_BGRA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadToNative<GLubyte, 4> ); + InsertD3D9FormatInfo(&map, GL_BGRA4_ANGLEX, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGRA4ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_BGR5_A1_ANGLEX, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGR5A1ToBGRA8 ); + + InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 8> ); + InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 8> ); + InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, D3DFMT_DXT3, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 16> ); + InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, D3DFMT_DXT5, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 16> ); + + // These formats require checking if the renderer supports D3DFMT_L8 or D3DFMT_A8L8 and + // then changing the format and loading function appropriately. + InsertD3D9FormatInfo(&map, GL_LUMINANCE8_EXT, D3DFMT_L8, D3DFMT_UNKNOWN, LoadToNative<GLubyte, 1> ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE8_ALPHA8_EXT, D3DFMT_A8L8, D3DFMT_UNKNOWN, LoadToNative<GLubyte, 2> ); + + return map; +} + +const TextureFormat &GetTextureFormatInfo(GLenum internalFormat) +{ + static const D3D9FormatMap formatMap = BuildD3D9FormatMap(); + D3D9FormatMap::const_iterator iter = formatMap.find(internalFormat); + if (iter != formatMap.end()) + { + return iter->second; + } + else + { + static const TextureFormat defaultInfo; + return defaultInfo; + } +} + +static GLenum GetDeclTypeComponentType(D3DDECLTYPE declType) +{ + switch (declType) + { + case D3DDECLTYPE_FLOAT1: return GL_FLOAT; + case D3DDECLTYPE_FLOAT2: return GL_FLOAT; + case D3DDECLTYPE_FLOAT3: return GL_FLOAT; + case D3DDECLTYPE_FLOAT4: return GL_FLOAT; + case D3DDECLTYPE_UBYTE4: return GL_UNSIGNED_INT; + case D3DDECLTYPE_SHORT2: return GL_INT; + case D3DDECLTYPE_SHORT4: return GL_INT; + case D3DDECLTYPE_UBYTE4N: return GL_UNSIGNED_NORMALIZED; + case D3DDECLTYPE_SHORT4N: return GL_SIGNED_NORMALIZED; + case D3DDECLTYPE_USHORT4N: return GL_UNSIGNED_NORMALIZED; + case D3DDECLTYPE_SHORT2N: return GL_SIGNED_NORMALIZED; + case D3DDECLTYPE_USHORT2N: return GL_UNSIGNED_NORMALIZED; + default: UNREACHABLE(); return GL_NONE; + } +} + +// Attribute format conversion +enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 }; + +struct TranslationDescription +{ + DWORD capsFlag; + VertexFormat preferredConversion; + VertexFormat fallbackConversion; +}; + +// Mapping from OpenGL-ES vertex attrib type to D3D decl type: +// +// BYTE SHORT (Cast) +// BYTE-norm FLOAT (Normalize) (can't be exactly represented as SHORT-norm) +// UNSIGNED_BYTE UBYTE4 (Identity) or SHORT (Cast) +// UNSIGNED_BYTE-norm UBYTE4N (Identity) or FLOAT (Normalize) +// SHORT SHORT (Identity) +// SHORT-norm SHORT-norm (Identity) or FLOAT (Normalize) +// UNSIGNED_SHORT FLOAT (Cast) +// UNSIGNED_SHORT-norm USHORT-norm (Identity) or FLOAT (Normalize) +// FIXED (not in WebGL) FLOAT (FixedToFloat) +// FLOAT FLOAT (Identity) + +// GLToCType maps from GL type (as GLenum) to the C typedef. +template <GLenum GLType> struct GLToCType { }; + +template <> struct GLToCType<GL_BYTE> { typedef GLbyte type; }; +template <> struct GLToCType<GL_UNSIGNED_BYTE> { typedef GLubyte type; }; +template <> struct GLToCType<GL_SHORT> { typedef GLshort type; }; +template <> struct GLToCType<GL_UNSIGNED_SHORT> { typedef GLushort type; }; +template <> struct GLToCType<GL_FIXED> { typedef GLuint type; }; +template <> struct GLToCType<GL_FLOAT> { typedef GLfloat type; }; + +// This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.) +enum D3DVertexType +{ + D3DVT_FLOAT, + D3DVT_SHORT, + D3DVT_SHORT_NORM, + D3DVT_UBYTE, + D3DVT_UBYTE_NORM, + D3DVT_USHORT_NORM +}; + +// D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type. +template <unsigned int D3DType> struct D3DToCType { }; + +template <> struct D3DToCType<D3DVT_FLOAT> { typedef float type; }; +template <> struct D3DToCType<D3DVT_SHORT> { typedef short type; }; +template <> struct D3DToCType<D3DVT_SHORT_NORM> { typedef short type; }; +template <> struct D3DToCType<D3DVT_UBYTE> { typedef unsigned char type; }; +template <> struct D3DToCType<D3DVT_UBYTE_NORM> { typedef unsigned char type; }; +template <> struct D3DToCType<D3DVT_USHORT_NORM> { typedef unsigned short type; }; + +// Encode the type/size combinations that D3D permits. For each type/size it expands to a widener that will provide the appropriate final size. +template <unsigned int type, int size> struct WidenRule { }; + +template <int size> struct WidenRule<D3DVT_FLOAT, size> : NoWiden<size> { }; +template <int size> struct WidenRule<D3DVT_SHORT, size> : WidenToEven<size> { }; +template <int size> struct WidenRule<D3DVT_SHORT_NORM, size> : WidenToEven<size> { }; +template <int size> struct WidenRule<D3DVT_UBYTE, size> : WidenToFour<size> { }; +template <int size> struct WidenRule<D3DVT_UBYTE_NORM, size> : WidenToFour<size> { }; +template <int size> struct WidenRule<D3DVT_USHORT_NORM, size> : WidenToEven<size> { }; + +// VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D vertex type & size combination. +template <unsigned int d3dtype, int size> struct VertexTypeFlags { }; + +template <unsigned int _capflag, unsigned int _declflag> +struct VertexTypeFlagsHelper +{ + enum { capflag = _capflag }; + enum { declflag = _declflag }; +}; + +template <> struct VertexTypeFlags<D3DVT_FLOAT, 1> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> { }; +template <> struct VertexTypeFlags<D3DVT_FLOAT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> { }; +template <> struct VertexTypeFlags<D3DVT_FLOAT, 3> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> { }; +template <> struct VertexTypeFlags<D3DVT_FLOAT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> { }; +template <> struct VertexTypeFlags<D3DVT_SHORT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> { }; +template <> struct VertexTypeFlags<D3DVT_SHORT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> { }; +template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT2N, D3DDECLTYPE_SHORT2N> { }; +template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT4N, D3DDECLTYPE_SHORT4N> { }; +template <> struct VertexTypeFlags<D3DVT_UBYTE, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4, D3DDECLTYPE_UBYTE4> { }; +template <> struct VertexTypeFlags<D3DVT_UBYTE_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4N, D3DDECLTYPE_UBYTE4N> { }; +template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT2N, D3DDECLTYPE_USHORT2N> { }; +template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT4N, D3DDECLTYPE_USHORT4N> { }; + + +// VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as D3DVertexType enums). +template <GLenum GLtype, bool normalized> struct VertexTypeMapping { }; + +template <D3DVertexType Preferred, D3DVertexType Fallback = Preferred> +struct VertexTypeMappingBase +{ + enum { preferred = Preferred }; + enum { fallback = Fallback }; +}; + +template <> struct VertexTypeMapping<GL_BYTE, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Cast +template <> struct VertexTypeMapping<GL_BYTE, true> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Normalize +template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, false> : VertexTypeMappingBase<D3DVT_UBYTE, D3DVT_FLOAT> { }; // Identity, Cast +template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, true> : VertexTypeMappingBase<D3DVT_UBYTE_NORM, D3DVT_FLOAT> { }; // Identity, Normalize +template <> struct VertexTypeMapping<GL_SHORT, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Identity +template <> struct VertexTypeMapping<GL_SHORT, true> : VertexTypeMappingBase<D3DVT_SHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize +template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, false> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Cast +template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, true> : VertexTypeMappingBase<D3DVT_USHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize +template <bool normalized> struct VertexTypeMapping<GL_FIXED, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // FixedToFloat +template <bool normalized> struct VertexTypeMapping<GL_FLOAT, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Identity + + +// Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule (Cast, Normalize, Identity, FixedToFloat). +// The conversion rules themselves are defined in vertexconversion.h. + +// Almost all cases are covered by Cast (including those that are actually Identity since Cast<T,T> knows it's an identity mapping). +template <GLenum fromType, bool normalized, unsigned int toType> +struct ConversionRule : Cast<typename GLToCType<fromType>::type, typename D3DToCType<toType>::type> { }; + +// All conversions from normalized types to float use the Normalize operator. +template <GLenum fromType> struct ConversionRule<fromType, true, D3DVT_FLOAT> : Normalize<typename GLToCType<fromType>::type> { }; + +// Use a full specialization for this so that it preferentially matches ahead of the generic normalize-to-float rules. +template <> struct ConversionRule<GL_FIXED, true, D3DVT_FLOAT> : FixedToFloat<GLint, 16> { }; +template <> struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : FixedToFloat<GLint, 16> { }; + +// A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues (i.e. 0/1) +// whether it is normalized or not. +template <class T, bool normalized> struct DefaultVertexValuesStage2 { }; + +template <class T> struct DefaultVertexValuesStage2<T, true> : NormalizedDefaultValues<T> { }; +template <class T> struct DefaultVertexValuesStage2<T, false> : SimpleDefaultValues<T> { }; + +// Work out the default value rule for a D3D type (expressed as the C type) and +template <class T, bool normalized> struct DefaultVertexValues : DefaultVertexValuesStage2<T, normalized> { }; +template <bool normalized> struct DefaultVertexValues<float, normalized> : SimpleDefaultValues<float> { }; + +// Policy rules for use with Converter, to choose whether to use the preferred or fallback conversion. +// The fallback conversion produces an output that all D3D9 devices must support. +template <class T> struct UsePreferred { enum { type = T::preferred }; }; +template <class T> struct UseFallback { enum { type = T::fallback }; }; + +// Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback conversion, +// it provides all the members of the appropriate VertexDataConverter, the D3DCAPS9::DeclTypes flag in cap flag +// and the D3DDECLTYPE member needed for the vertex declaration in declflag. +template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule> +struct Converter + : VertexDataConverter<typename GLToCType<fromType>::type, + WidenRule<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type, size>, + ConversionRule<fromType, + normalized, + PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>, + DefaultVertexValues<typename D3DToCType<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>::type, normalized > > +{ +private: + enum { d3dtype = PreferenceRule< VertexTypeMapping<fromType, normalized> >::type }; + enum { d3dsize = WidenRule<d3dtype, size>::finalWidth }; + +public: + enum { capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag }; + enum { declflag = VertexTypeFlags<d3dtype, d3dsize>::declflag }; +}; + +VertexFormat::VertexFormat() + : conversionType(VERTEX_CONVERT_NONE), + outputElementSize(0), + copyFunction(NULL), + nativeFormat(D3DDECLTYPE_UNUSED), + componentType(GL_NONE) +{ +} + +// Initialize a TranslationInfo +VertexFormat CreateVertexFormatInfo(bool identity, size_t elementSize, VertexCopyFunction copyFunc, D3DDECLTYPE nativeFormat) +{ + VertexFormat formatInfo; + formatInfo.conversionType = identity ? VERTEX_CONVERT_NONE : VERTEX_CONVERT_CPU; + formatInfo.outputElementSize = elementSize; + formatInfo.copyFunction = copyFunc; + formatInfo.nativeFormat = nativeFormat; + formatInfo.componentType = GetDeclTypeComponentType(nativeFormat); + return formatInfo; +} + +#define TRANSLATION(type, norm, size, preferred) \ + CreateVertexFormatInfo \ + ( \ + Converter<type, norm, size, preferred>::identity, \ + Converter<type, norm, size, preferred>::finalSize, \ + Converter<type, norm, size, preferred>::convertArray, \ + static_cast<D3DDECLTYPE>(Converter<type, norm, size, preferred>::declflag) \ + ) + +#define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size) \ + { \ + Converter<type, norm, size, UsePreferred>::capflag, \ + TRANSLATION(type, norm, size, UsePreferred), \ + TRANSLATION(type, norm, size, UseFallback) \ + } + +#define TRANSLATIONS_FOR_TYPE(type) \ + { \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 4) }, \ + } + +#define TRANSLATIONS_FOR_TYPE_NO_NORM(type) \ + { \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ + } + +static inline unsigned int ComputeTypeIndex(GLenum type) +{ + switch (type) + { + case GL_BYTE: return 0; + case GL_UNSIGNED_BYTE: return 1; + case GL_SHORT: return 2; + case GL_UNSIGNED_SHORT: return 3; + case GL_FIXED: return 4; + case GL_FLOAT: return 5; + + default: UNREACHABLE(); return 5; + } +} + +const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, const gl::VertexFormat &vertexFormat) +{ + static bool initialized = false; + static DWORD intializedDeclTypes = 0; + static VertexFormat formatConverters[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; + if (!initialized) + { + const TranslationDescription translations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1] + { + TRANSLATIONS_FOR_TYPE(GL_BYTE), + TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE), + TRANSLATIONS_FOR_TYPE(GL_SHORT), + TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT), + TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FIXED), + TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FLOAT) + }; + for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++) + { + for (unsigned int j = 0; j < 2; j++) + { + for (unsigned int k = 0; k < 4; k++) + { + if (translations[i][j][k].capsFlag == 0 || (supportedDeclTypes & translations[i][j][k].capsFlag) != 0) + { + formatConverters[i][j][k] = translations[i][j][k].preferredConversion; + } + else + { + formatConverters[i][j][k] = translations[i][j][k].fallbackConversion; + } + } + } + } + initialized = true; + intializedDeclTypes = supportedDeclTypes; + } + + ASSERT(intializedDeclTypes == supportedDeclTypes); + + // Pure integer attributes only supported in ES3.0 + ASSERT(!vertexFormat.mPureInteger); + return formatConverters[ComputeTypeIndex(vertexFormat.mType)][vertexFormat.mNormalized][vertexFormat.mComponents - 1]; +} + +} + +} 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..f26fe43b36 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.h @@ -0,0 +1,74 @@ +// +// 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" + +#include <map> + +namespace rx +{ + +class Renderer9; + +namespace d3d9 +{ + +typedef std::map<std::pair<GLenum, GLenum>, ColorCopyFunction> FastCopyFunctionMap; + +struct D3DFormat +{ + D3DFormat(); + + GLuint pixelBytes; + GLuint blockWidth; + GLuint blockHeight; + + GLenum internalFormat; + + MipGenerationFunction mipGenerationFunction; + ColorReadFunction colorReadFunction; + + FastCopyFunctionMap fastCopyFunctions; + ColorCopyFunction getFastCopyFunction(GLenum format, GLenum type) const; +}; +const D3DFormat &GetD3DFormatInfo(D3DFORMAT format); + +struct VertexFormat +{ + VertexFormat(); + + VertexConversionType conversionType; + size_t outputElementSize; + VertexCopyFunction copyFunction; + D3DDECLTYPE nativeFormat; + GLenum componentType; +}; +const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, const gl::VertexFormat &vertexFormat); + +struct TextureFormat +{ + TextureFormat(); + + D3DFORMAT texFormat; + D3DFORMAT renderFormat; + + InitializeTextureDataFunction dataInitializerFunction; + + LoadImageFunction loadFunction; +}; +const TextureFormat &GetTextureFormatInfo(GLenum internalFormat); + +} + +} + +#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..e7a91e62d6 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp @@ -0,0 +1,542 @@ +// +// 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 "libGLESv2/Framebuffer.h" +#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" + +#include "common/mathutil.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; + } +} + +D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples) +{ + return (samples > 1) ? static_cast<D3DMULTISAMPLE_TYPE>(samples) : D3DMULTISAMPLE_NONE; +} + +} + +namespace d3d9_gl +{ + +GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type) +{ + return (type != D3DMULTISAMPLE_NONMASKABLE) ? type : 0; +} + +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format) +{ + GLenum internalFormat = d3d9::GetD3DFormatInfo(d3dformat).internalFormat; + GLenum convertedFormat = gl::GetInternalFormatInfo(internalFormat).format; + return convertedFormat == format; +} + +static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, IDirect3D9 *d3d9, D3DDEVTYPE deviceType, + UINT adapter, D3DFORMAT adapterFormat) +{ + gl::TextureCaps textureCaps; + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalFormat); + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)); + } + else + { + textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)) && + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_CUBETEXTURE, d3dFormatInfo.texFormat)); + } + + textureCaps.filterable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)); + textureCaps.renderable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat)) || + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat)); + + 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, d3dFormatInfo.renderFormat, TRUE, multisampleType, NULL); + if (SUCCEEDED(result)) + { + textureCaps.sampleCounts.insert(i); + } + } + + return textureCaps; +} + +void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceType, UINT adapter, gl::Caps *caps, + gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions) +{ + D3DCAPS9 deviceCaps; + if (FAILED(d3d9->GetDeviceCaps(adapter, deviceType, &deviceCaps))) + { + // Can't continue with out device caps + return; + } + + D3DDISPLAYMODE currentDisplayMode; + d3d9->GetAdapterDisplayMode(adapter, ¤tDisplayMode); + + GLuint maxSamples = 0; + const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats(); + for (gl::FormatSet::const_iterator internalFormat = allFormats.begin(); internalFormat != allFormats.end(); ++internalFormat) + { + gl::TextureCaps textureCaps = GenerateTextureFormatCaps(*internalFormat, d3d9, deviceType, adapter, + currentDisplayMode.Format); + textureCapsMap->insert(*internalFormat, textureCaps); + + maxSamples = std::max(maxSamples, textureCaps.getMaxSamples()); + + if (gl::GetInternalFormatInfo(*internalFormat).compressed) + { + caps->compressedTextureFormats.push_back(*internalFormat); + } + } + + // GL core feature limits + caps->maxElementIndex = static_cast<GLint64>(std::numeric_limits<unsigned int>::max()); + + // 3D textures are unimplemented in D3D9 + caps->max3DTextureSize = 1; + + // Only one limit in GL, use the minimum dimension + caps->max2DTextureSize = std::min(deviceCaps.MaxTextureWidth, deviceCaps.MaxTextureHeight); + + // D3D treats cube maps as a special case of 2D textures + caps->maxCubeMapTextureSize = caps->max2DTextureSize; + + // Array textures are not available in D3D9 + caps->maxArrayTextureLayers = 1; + + // ES3-only feature + caps->maxLODBias = 0.0f; + + // No specific limits on render target size, maximum 2D texture size is equivalent + caps->maxRenderbufferSize = caps->max2DTextureSize; + + // Draw buffers are not supported in D3D9 + caps->maxDrawBuffers = 1; + caps->maxColorAttachments = 1; + + // No specific limits on viewport size, maximum 2D texture size is equivalent + caps->maxViewportWidth = caps->max2DTextureSize; + caps->maxViewportHeight = caps->maxViewportWidth; + + // Point size is clamped to 1.0f when the shader model is less than 3 + caps->minAliasedPointSize = 1.0f; + caps->maxAliasedPointSize = ((D3DSHADER_VERSION_MAJOR(deviceCaps.PixelShaderVersion) >= 3) ? deviceCaps.MaxPointSize : 1.0f); + + // Wide lines not supported + caps->minAliasedLineWidth = 1.0f; + caps->maxAliasedLineWidth = 1.0f; + + // Primitive count limits (unused in ES2) + caps->maxElementsIndices = 0; + caps->maxElementsVertices = 0; + + // Program and shader binary formats (no supported shader binary formats) + caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE); + + // WaitSync is ES3-only, set to zero + caps->maxServerWaitTimeout = 0; + + // Vertex shader limits + caps->maxVertexAttributes = 16; + + const size_t reservedVertexUniformVectors = 2; // dx_ViewAdjust and dx_DepthRange. + const size_t MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256; + caps->maxVertexUniformVectors = MAX_VERTEX_CONSTANT_VECTORS_D3D9 - reservedVertexUniformVectors; + caps->maxVertexUniformComponents = caps->maxVertexUniformVectors * 4; + + caps->maxVertexUniformBlocks = 0; + + const size_t MAX_VERTEX_OUTPUT_VECTORS_SM3 = 10; + const size_t MAX_VERTEX_OUTPUT_VECTORS_SM2 = 8; + caps->maxVertexOutputComponents = ((deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0)) ? MAX_VERTEX_OUTPUT_VECTORS_SM3 + : MAX_VERTEX_OUTPUT_VECTORS_SM2) * 4; + + // Only Direct3D 10 ready devices support all the necessary vertex texture formats. + // We test this using D3D9 by checking support for the R16F format. + if (deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0) && + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, currentDisplayMode.Format, + D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F))) + { + const size_t MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4; + caps->maxVertexTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS_VTF_SM3; + } + else + { + caps->maxVertexTextureImageUnits = 0; + } + + // Fragment shader limits + const size_t reservedPixelUniformVectors = 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange. + + const size_t MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224; + const size_t MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32; + caps->maxFragmentUniformVectors = ((deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) ? MAX_PIXEL_CONSTANT_VECTORS_SM3 + : MAX_PIXEL_CONSTANT_VECTORS_SM2) - reservedPixelUniformVectors; + caps->maxFragmentUniformComponents = caps->maxFragmentUniformVectors * 4; + caps->maxFragmentUniformBlocks = 0; + caps->maxFragmentInputComponents = caps->maxVertexOutputComponents; + caps->maxTextureImageUnits = 16; + caps->minProgramTexelOffset = 0; + caps->maxProgramTexelOffset = 0; + + // Aggregate shader limits (unused in ES2) + caps->maxUniformBufferBindings = 0; + caps->maxUniformBlockSize = 0; + caps->uniformBufferOffsetAlignment = 0; + caps->maxCombinedUniformBlocks = 0; + caps->maxCombinedVertexUniformComponents = 0; + caps->maxCombinedFragmentUniformComponents = 0; + caps->maxVaryingComponents = 0; + + // Aggregate shader limits + caps->maxVaryingVectors = caps->maxVertexOutputComponents / 4; + caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits; + + // Transform feedback limits + caps->maxTransformFeedbackInterleavedComponents = 0; + caps->maxTransformFeedbackSeparateAttributes = 0; + caps->maxTransformFeedbackSeparateComponents = 0; + + // 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->maxSamples = maxSamples; + 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; +} + +} + +namespace d3d9 +{ + +GLuint ComputeBlockSize(D3DFORMAT format, GLuint width, GLuint height) +{ + const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format); + GLuint numBlocksWide = (width + d3dFormatInfo.blockWidth - 1) / d3dFormatInfo.blockWidth; + GLuint numBlocksHight = (height + d3dFormatInfo.blockHeight - 1) / d3dFormatInfo.blockHeight; + return (d3dFormatInfo.pixelBytes * numBlocksWide * numBlocksHight); +} + +void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset) +{ + const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format); + + int upsampleCount = 0; + // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already. + if (isImage || *requestWidth < static_cast<GLsizei>(d3dFormatInfo.blockWidth) || + *requestHeight < static_cast<GLsizei>(d3dFormatInfo.blockHeight)) + { + while (*requestWidth % d3dFormatInfo.blockWidth != 0 || *requestHeight % d3dFormatInfo.blockHeight != 0) + { + *requestWidth <<= 1; + *requestHeight <<= 1; + upsampleCount++; + } + } + *levelOffset = upsampleCount; +} + +RenderTarget9 *GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment) +{ + RenderTarget *renderTarget = rx::GetAttachmentRenderTarget(attachment); + return RenderTarget9::makeRenderTarget9(renderTarget); +} + +} + +} 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..b0a940e60a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.h @@ -0,0 +1,83 @@ +// +// 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 gl +{ +class FramebufferAttachment; +} + +namespace rx +{ +class RenderTarget9; + +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); + +D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples); + +} + +namespace d3d9_gl +{ + +GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type); + +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format); + +void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceType, UINT adapter, gl::Caps *caps, + gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions); + +} + +namespace d3d9 +{ + +GLuint ComputeBlockSize(D3DFORMAT format, GLuint width, GLuint height); + +void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset); + +inline bool isDeviceLostError(HRESULT errorCode) +{ + switch (errorCode) + { + case D3DERR_DRIVERINTERNALERROR: + case D3DERR_DEVICELOST: + case D3DERR_DEVICEHUNG: + case D3DERR_DEVICEREMOVED: + return true; + default: + return false; + } +} + +RenderTarget9 *GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment); + +} + +} + +#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; +}; |