diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9 | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9')
51 files changed, 13516 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp new file mode 100644 index 0000000000..44362bd11a --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp @@ -0,0 +1,760 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Blit9.cpp: Surface copy utility class. + +#include "libANGLE/renderer/d3d/d3d9/Blit9.h" + +#include "libANGLE/Context.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" + +namespace +{ +// Precompiled shaders +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskpremultps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskunmultps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminancepremultps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceunmultps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/passthroughps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/standardvs.h" + +const BYTE *const g_shaderCode[] = { + g_vs20_standardvs, + g_ps20_passthroughps, + g_ps20_luminanceps, + g_ps20_luminancepremultps, + g_ps20_luminanceunmultps, + g_ps20_componentmaskps, + g_ps20_componentmaskpremultps, + g_ps20_componentmaskunmultps, +}; + +const size_t g_shaderSize[] = { + sizeof(g_vs20_standardvs), + sizeof(g_ps20_passthroughps), + sizeof(g_ps20_luminanceps), + sizeof(g_ps20_luminancepremultps), + sizeof(g_ps20_luminanceunmultps), + sizeof(g_ps20_componentmaskps), + sizeof(g_ps20_componentmaskpremultps), + sizeof(g_ps20_componentmaskunmultps), +}; +} // namespace + +namespace rx +{ + +Blit9::Blit9(Renderer9 *renderer) + : mRenderer(renderer), + mGeometryLoaded(false), + mQuadVertexBuffer(nullptr), + mQuadVertexDeclaration(nullptr), + mSavedStateBlock(nullptr), + mSavedRenderTarget(nullptr), + mSavedDepthStencil(nullptr) +{ + memset(mCompiledShaders, 0, sizeof(mCompiledShaders)); +} + +Blit9::~Blit9() +{ + SafeRelease(mSavedStateBlock); + SafeRelease(mQuadVertexBuffer); + SafeRelease(mQuadVertexDeclaration); + + for (int i = 0; i < SHADER_COUNT; i++) + { + SafeRelease(mCompiledShaders[i]); + } +} + +angle::Result Blit9::initialize(Context9 *context9) +{ + if (mGeometryLoaded) + { + return angle::Result::Continue; + } + + static const float quad[] = {-1, -1, -1, 1, 1, -1, 1, 1}; + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, + D3DPOOL_DEFAULT, &mQuadVertexBuffer, nullptr); + + ANGLE_TRY_HR(context9, result, "Failed to create internal blit vertex shader"); + + void *lockPtr = nullptr; + result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0); + + ANGLE_TRY_HR(context9, result, "Failed to lock internal blit vertex shader"); + ASSERT(lockPtr); + + memcpy(lockPtr, quad, sizeof(quad)); + mQuadVertexBuffer->Unlock(); + + static const D3DVERTEXELEMENT9 elements[] = { + {0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, D3DDECL_END()}; + + result = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration); + ANGLE_TRY_HR(context9, result, "Failed to create internal blit vertex shader declaration"); + + mGeometryLoaded = true; + return angle::Result::Continue; +} + +template <class D3DShaderType> +angle::Result Blit9::setShader(Context9 *context9, + ShaderId source, + const char *profile, + angle::Result (Renderer9::*createShader)(d3d::Context *, + const DWORD *, + size_t length, + D3DShaderType **outShader), + HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType *)) +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + D3DShaderType *shader = nullptr; + + if (mCompiledShaders[source] != nullptr) + { + shader = static_cast<D3DShaderType *>(mCompiledShaders[source]); + } + else + { + const BYTE *shaderCode = g_shaderCode[source]; + size_t shaderSize = g_shaderSize[source]; + ANGLE_TRY((mRenderer->*createShader)(context9, reinterpret_cast<const DWORD *>(shaderCode), + shaderSize, &shader)); + mCompiledShaders[source] = shader; + } + + HRESULT hr = (device->*setShader)(shader); + ANGLE_TRY_HR(context9, hr, "Failed to set shader for blit operation"); + return angle::Result::Continue; +} + +angle::Result Blit9::setVertexShader(Context9 *context9, ShaderId shader) +{ + return setShader<IDirect3DVertexShader9>(context9, shader, "vs_2_0", + &Renderer9::createVertexShader, + &IDirect3DDevice9::SetVertexShader); +} + +angle::Result Blit9::setPixelShader(Context9 *context9, ShaderId shader) +{ + return setShader<IDirect3DPixelShader9>(context9, shader, "ps_2_0", + &Renderer9::createPixelShader, + &IDirect3DDevice9::SetPixelShader); +} + +RECT Blit9::getSurfaceRect(IDirect3DSurface9 *surface) const +{ + D3DSURFACE_DESC desc; + surface->GetDesc(&desc); + + RECT rect; + rect.left = 0; + rect.top = 0; + rect.right = desc.Width; + rect.bottom = desc.Height; + + return rect; +} + +gl::Extents Blit9::getSurfaceSize(IDirect3DSurface9 *surface) const +{ + D3DSURFACE_DESC desc; + surface->GetDesc(&desc); + + return gl::Extents(desc.Width, desc.Height, 1); +} + +angle::Result Blit9::boxFilter(Context9 *context9, + IDirect3DSurface9 *source, + IDirect3DSurface9 *dest) +{ + ANGLE_TRY(initialize(context9)); + + angle::ComPtr<IDirect3DBaseTexture9> texture = nullptr; + ANGLE_TRY(copySurfaceToTexture(context9, source, getSurfaceRect(source), &texture)); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + saveState(); + + device->SetTexture(0, texture.Get()); + device->SetRenderTarget(0, dest); + + ANGLE_TRY(setVertexShader(context9, SHADER_VS_STANDARD)); + ANGLE_TRY(setPixelShader(context9, SHADER_PS_PASSTHROUGH)); + + setCommonBlitState(); + device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + + setViewportAndShaderConstants(getSurfaceRect(source), getSurfaceSize(source), + getSurfaceRect(dest), false); + + render(); + + restoreState(); + + return angle::Result::Continue; +} + +angle::Result Blit9::copy2D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) +{ + Context9 *context9 = GetImplAs<Context9>(context); + + ANGLE_TRY(initialize(context9)); + + const gl::FramebufferAttachment *colorbuffer = framebuffer->getColorAttachment(0); + ASSERT(colorbuffer); + + RenderTarget9 *renderTarget9 = nullptr; + ANGLE_TRY(colorbuffer->getRenderTarget(context, &renderTarget9)); + ASSERT(renderTarget9); + + angle::ComPtr<IDirect3DSurface9> source = renderTarget9->getSurface(); + ASSERT(source); + + angle::ComPtr<IDirect3DSurface9> destSurface = nullptr; + TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage); + ANGLE_TRY( + storage9->getSurfaceLevel(context, gl::TextureTarget::_2D, level, true, &destSurface)); + ASSERT(destSurface); + + ANGLE_TRY(copy(context9, source.Get(), nullptr, sourceRect, destFormat, destOffset, + destSurface.Get(), false, false, false)); + return angle::Result::Continue; +} + +angle::Result Blit9::copyCube(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + gl::TextureTarget target, + GLint level) +{ + Context9 *context9 = GetImplAs<Context9>(context); + + ANGLE_TRY(initialize(context9)); + + const gl::FramebufferAttachment *colorbuffer = framebuffer->getColorAttachment(0); + ASSERT(colorbuffer); + + RenderTarget9 *renderTarget9 = nullptr; + ANGLE_TRY(colorbuffer->getRenderTarget(context, &renderTarget9)); + ASSERT(renderTarget9); + + angle::ComPtr<IDirect3DSurface9> source = renderTarget9->getSurface(); + ASSERT(source); + + angle::ComPtr<IDirect3DSurface9> destSurface = nullptr; + TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage); + ANGLE_TRY(storage9->getSurfaceLevel(context, target, level, true, &destSurface)); + ASSERT(destSurface); + + return copy(context9, source.Get(), nullptr, sourceRect, destFormat, destOffset, + destSurface.Get(), false, false, false); +} + +angle::Result Blit9::copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + gl::TextureTarget destTarget, + GLint destLevel, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha) +{ + Context9 *context9 = GetImplAs<Context9>(context); + ANGLE_TRY(initialize(context9)); + + TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source); + + TextureStorage *sourceStorage = nullptr; + ANGLE_TRY(sourceD3D->getNativeTexture(context, &sourceStorage)); + + TextureStorage9_2D *sourceStorage9 = GetAs<TextureStorage9_2D>(sourceStorage); + ASSERT(sourceStorage9); + + TextureStorage9 *destStorage9 = GetAs<TextureStorage9>(storage); + ASSERT(destStorage9); + + ASSERT(sourceLevel == 0); + IDirect3DBaseTexture9 *sourceTexture = nullptr; + ANGLE_TRY(sourceStorage9->getBaseTexture(context, &sourceTexture)); + + angle::ComPtr<IDirect3DSurface9> sourceSurface = nullptr; + ANGLE_TRY(sourceStorage9->getSurfaceLevel(context, gl::TextureTarget::_2D, sourceLevel, true, + &sourceSurface)); + + angle::ComPtr<IDirect3DSurface9> destSurface = nullptr; + ANGLE_TRY(destStorage9->getSurfaceLevel(context, destTarget, destLevel, true, &destSurface)); + + return copy(context9, sourceSurface.Get(), sourceTexture, sourceRect, destFormat, destOffset, + destSurface.Get(), flipY, premultiplyAlpha, unmultiplyAlpha); +} + +angle::Result Blit9::copy(Context9 *context9, + IDirect3DSurface9 *source, + IDirect3DBaseTexture9 *sourceTexture, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + IDirect3DSurface9 *dest, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha) +{ + ASSERT(source != nullptr && dest != nullptr); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + D3DSURFACE_DESC sourceDesc; + D3DSURFACE_DESC destDesc; + source->GetDesc(&sourceDesc); + dest->GetDesc(&destDesc); + + // Check if it's possible to use StetchRect + if (sourceDesc.Format == destDesc.Format && (destDesc.Usage & D3DUSAGE_RENDERTARGET) && + d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat) && !flipY && + premultiplyAlpha == unmultiplyAlpha) + { + RECT destRect = {destOffset.x, destOffset.y, + destOffset.x + (sourceRect.right - sourceRect.left), + destOffset.y + (sourceRect.bottom - sourceRect.top)}; + HRESULT result = device->StretchRect(source, &sourceRect, dest, &destRect, D3DTEXF_POINT); + ANGLE_TRY_HR(context9, result, "StretchRect failed to blit between textures"); + return angle::Result::Continue; + } + + angle::ComPtr<IDirect3DBaseTexture9> texture = sourceTexture; + RECT adjustedSourceRect = sourceRect; + gl::Extents sourceSize(sourceDesc.Width, sourceDesc.Height, 1); + + if (texture == nullptr) + { + ANGLE_TRY(copySurfaceToTexture(context9, source, sourceRect, &texture)); + + // copySurfaceToTexture only copies in the sourceRect area of the source surface. + // Adjust sourceRect so that it is now covering the entire source texture + adjustedSourceRect.left = 0; + adjustedSourceRect.right = sourceRect.right - sourceRect.left; + adjustedSourceRect.top = 0; + adjustedSourceRect.bottom = sourceRect.bottom - sourceRect.top; + + sourceSize.width = sourceRect.right - sourceRect.left; + sourceSize.height = sourceRect.bottom - sourceRect.top; + } + + ANGLE_TRY(formatConvert(context9, texture.Get(), adjustedSourceRect, sourceSize, destFormat, + destOffset, dest, flipY, premultiplyAlpha, unmultiplyAlpha)); + return angle::Result::Continue; +} + +angle::Result Blit9::formatConvert(Context9 *context9, + IDirect3DBaseTexture9 *source, + const RECT &sourceRect, + const gl::Extents &sourceSize, + GLenum destFormat, + const gl::Offset &destOffset, + IDirect3DSurface9 *dest, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha) +{ + ANGLE_TRY(initialize(context9)); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + saveState(); + + device->SetTexture(0, source); + device->SetRenderTarget(0, dest); + + RECT destRect; + destRect.left = destOffset.x; + destRect.right = destOffset.x + (sourceRect.right - sourceRect.left); + destRect.top = destOffset.y; + destRect.bottom = destOffset.y + (sourceRect.bottom - sourceRect.top); + + setViewportAndShaderConstants(sourceRect, sourceSize, destRect, flipY); + + setCommonBlitState(); + + angle::Result result = + setFormatConvertShaders(context9, destFormat, flipY, premultiplyAlpha, unmultiplyAlpha); + if (result == angle::Result::Continue) + { + render(); + } + + restoreState(); + + return result; +} + +angle::Result Blit9::setFormatConvertShaders(Context9 *context9, + GLenum destFormat, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha) +{ + ANGLE_TRY(setVertexShader(context9, SHADER_VS_STANDARD)); + + switch (destFormat) + { + case GL_RGBA: + case GL_BGRA_EXT: + case GL_RGB: + case GL_RG_EXT: + case GL_RED_EXT: + case GL_ALPHA: + if (premultiplyAlpha == unmultiplyAlpha) + { + ANGLE_TRY(setPixelShader(context9, SHADER_PS_COMPONENTMASK)); + } + else if (premultiplyAlpha) + { + ANGLE_TRY(setPixelShader(context9, SHADER_PS_COMPONENTMASK_PREMULTIPLY_ALPHA)); + } + else + { + ASSERT(unmultiplyAlpha); + ANGLE_TRY(setPixelShader(context9, SHADER_PS_COMPONENTMASK_UNMULTIPLY_ALPHA)); + } + break; + + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + if (premultiplyAlpha == unmultiplyAlpha) + { + ANGLE_TRY(setPixelShader(context9, SHADER_PS_LUMINANCE)); + } + else if (premultiplyAlpha) + { + ANGLE_TRY(setPixelShader(context9, SHADER_PS_LUMINANCE_PREMULTIPLY_ALPHA)); + } + else + { + ASSERT(unmultiplyAlpha); + ANGLE_TRY(setPixelShader(context9, SHADER_PS_LUMINANCE_UNMULTIPLY_ALPHA)); + } + break; + + default: + UNREACHABLE(); + } + + enum + { + X = 0, + Y = 1, + Z = 2, + W = 3 + }; + + // The meaning of this constant depends on the shader that was selected. + // See the shader assembly code above for details. + // Allocate one array for both registers and split it into two float4's. + float psConst[8] = {0}; + float *multConst = &psConst[0]; + float *addConst = &psConst[4]; + + switch (destFormat) + { + case GL_RGBA: + case GL_BGRA_EXT: + multConst[X] = 1; + multConst[Y] = 1; + multConst[Z] = 1; + multConst[W] = 1; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 0; + break; + + case GL_RGB: + multConst[X] = 1; + multConst[Y] = 1; + multConst[Z] = 1; + multConst[W] = 0; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 1; + break; + + case GL_RG_EXT: + multConst[X] = 1; + multConst[Y] = 1; + multConst[Z] = 0; + multConst[W] = 0; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 1; + break; + + case GL_RED_EXT: + multConst[X] = 1; + multConst[Y] = 0; + multConst[Z] = 0; + multConst[W] = 0; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 1; + break; + + case GL_ALPHA: + multConst[X] = 0; + multConst[Y] = 0; + multConst[Z] = 0; + multConst[W] = 1; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 0; + break; + + case GL_LUMINANCE: + multConst[X] = 1; + multConst[Y] = 0; + multConst[Z] = 0; + multConst[W] = 0; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 1; + break; + + case GL_LUMINANCE_ALPHA: + multConst[X] = 1; + multConst[Y] = 0; + multConst[Z] = 0; + multConst[W] = 1; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 0; + break; + + default: + UNREACHABLE(); + } + + mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst, 2); + + return angle::Result::Continue; +} + +angle::Result Blit9::copySurfaceToTexture(Context9 *context9, + IDirect3DSurface9 *surface, + const RECT &sourceRect, + angle::ComPtr<IDirect3DBaseTexture9> *outTexture) +{ + ASSERT(surface); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + D3DSURFACE_DESC sourceDesc; + surface->GetDesc(&sourceDesc); + + // Copy the render target into a texture + angle::ComPtr<IDirect3DTexture9> texture; + HRESULT result = device->CreateTexture( + sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1, + D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, nullptr); + ANGLE_TRY_HR(context9, result, "Failed to allocate internal texture for blit"); + + angle::ComPtr<IDirect3DSurface9> textureSurface; + result = texture->GetSurfaceLevel(0, &textureSurface); + ANGLE_TRY_HR(context9, result, "Failed to query surface of internal blit texture"); + + mRenderer->endScene(); + result = device->StretchRect(surface, &sourceRect, textureSurface.Get(), nullptr, D3DTEXF_NONE); + ANGLE_TRY_HR(context9, result, "Failed to copy between internal blit textures"); + *outTexture = texture; + + return angle::Result::Continue; +} + +void Blit9::setViewportAndShaderConstants(const RECT &sourceRect, + const gl::Extents &sourceSize, + const RECT &destRect, + bool flipY) +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + D3DVIEWPORT9 vp; + vp.X = destRect.left; + vp.Y = destRect.top; + vp.Width = destRect.right - destRect.left; + vp.Height = destRect.bottom - destRect.top; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + device->SetViewport(&vp); + + float vertexConstants[8] = { + // halfPixelAdjust + -1.0f / vp.Width, + 1.0f / vp.Height, + 0, + 0, + // texcoordOffset + static_cast<float>(sourceRect.left) / sourceSize.width, + static_cast<float>(flipY ? sourceRect.bottom : sourceRect.top) / sourceSize.height, + static_cast<float>(sourceRect.right - sourceRect.left) / sourceSize.width, + static_cast<float>(flipY ? sourceRect.top - sourceRect.bottom + : sourceRect.bottom - sourceRect.top) / + sourceSize.height, + }; + + device->SetVertexShaderConstantF(0, vertexConstants, 2); +} + +void Blit9::setCommonBlitState() +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + device->SetDepthStencilSurface(nullptr); + + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + device->SetRenderState(D3DRS_COLORWRITEENABLE, + D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | + D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE); + device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + + device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE); + device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + + RECT scissorRect = {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 == nullptr) + { + hr = device->BeginStateBlock(); + ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + + setCommonBlitState(); + + static const float dummyConst[8] = {0}; + + device->SetVertexShader(nullptr); + device->SetVertexShaderConstantF(0, dummyConst, 2); + device->SetPixelShader(nullptr); + 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, nullptr); + + device->SetStreamSource(0, mQuadVertexBuffer, 0, 0); + + device->SetVertexDeclaration(mQuadVertexDeclaration); + + hr = device->EndStateBlock(&mSavedStateBlock); + ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + } + + ASSERT(mSavedStateBlock != nullptr); + + if (mSavedStateBlock != nullptr) + { + hr = mSavedStateBlock->Capture(); + ASSERT(SUCCEEDED(hr)); + } +} + +void Blit9::restoreState() +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + device->SetDepthStencilSurface(mSavedDepthStencil); + SafeRelease(mSavedDepthStencil); + + device->SetRenderTarget(0, mSavedRenderTarget); + SafeRelease(mSavedRenderTarget); + + ASSERT(mSavedStateBlock != nullptr); + + if (mSavedStateBlock != nullptr) + { + mSavedStateBlock->Apply(); + } +} +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Blit9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Blit9.h new file mode 100644 index 0000000000..5617552069 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Blit9.h @@ -0,0 +1,166 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Blit9.cpp: Surface copy utility class. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_BLIT9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_BLIT9_H_ + +#include "common/PackedEnums.h" +#include "common/angleutils.h" +#include "libANGLE/Error.h" + +namespace gl +{ +class Context; +class Framebuffer; +class Texture; +struct Extents; +struct Offset; +} // namespace gl + +namespace rx +{ +class Context9; +class Renderer9; +class TextureStorage; + +namespace d3d +{ +class Context; +} // namespace d3d + +class Blit9 : angle::NonCopyable +{ + public: + explicit Blit9(Renderer9 *renderer); + ~Blit9(); + + angle::Result initialize(Context9 *context9); + + // Copy from source surface to dest surface. + // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) + angle::Result copy2D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level); + angle::Result copyCube(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + gl::TextureTarget target, + GLint level); + angle::Result copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + gl::TextureTarget destTarget, + GLint destLevel, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha); + + // 2x2 box filter sample from source to dest. + // Requires that source is RGB(A) and dest has the same format as source. + angle::Result boxFilter(Context9 *context9, IDirect3DSurface9 *source, IDirect3DSurface9 *dest); + + private: + Renderer9 *mRenderer; + + bool mGeometryLoaded; + IDirect3DVertexBuffer9 *mQuadVertexBuffer; + IDirect3DVertexDeclaration9 *mQuadVertexDeclaration; + + // Copy from source texture 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. + angle::Result formatConvert(Context9 *context9, + IDirect3DBaseTexture9 *source, + const RECT &sourceRect, + const gl::Extents &sourceSize, + GLenum destFormat, + const gl::Offset &destOffset, + IDirect3DSurface9 *dest, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha); + angle::Result setFormatConvertShaders(Context9 *context9, + GLenum destFormat, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha); + + angle::Result copy(Context9 *context9, + IDirect3DSurface9 *source, + IDirect3DBaseTexture9 *sourceTexture, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + IDirect3DSurface9 *dest, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha); + angle::Result copySurfaceToTexture(Context9 *context9, + IDirect3DSurface9 *surface, + const RECT &sourceRect, + angle::ComPtr<IDirect3DBaseTexture9> *outTexture); + void setViewportAndShaderConstants(const RECT &sourceRect, + const gl::Extents &sourceSize, + const RECT &destRect, + bool flipY); + void setCommonBlitState(); + RECT getSurfaceRect(IDirect3DSurface9 *surface) const; + gl::Extents getSurfaceSize(IDirect3DSurface9 *surface) const; + + // This enum is used to index mCompiledShaders and mShaderSource. + enum ShaderId + { + SHADER_VS_STANDARD, + SHADER_PS_PASSTHROUGH, + SHADER_PS_LUMINANCE, + SHADER_PS_LUMINANCE_PREMULTIPLY_ALPHA, + SHADER_PS_LUMINANCE_UNMULTIPLY_ALPHA, + SHADER_PS_COMPONENTMASK, + SHADER_PS_COMPONENTMASK_PREMULTIPLY_ALPHA, + SHADER_PS_COMPONENTMASK_UNMULTIPLY_ALPHA, + SHADER_COUNT, + }; + + // This actually contains IDirect3DVertexShader9 or IDirect3DPixelShader9 casted to IUnknown. + IUnknown *mCompiledShaders[SHADER_COUNT]; + + template <class D3DShaderType> + angle::Result setShader(Context9 *, + ShaderId source, + const char *profile, + angle::Result (Renderer9::*createShader)(d3d::Context *context, + const DWORD *, + size_t length, + D3DShaderType **outShader), + HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType *)); + + angle::Result setVertexShader(Context9 *context9, ShaderId shader); + angle::Result setPixelShader(Context9 *context9, ShaderId shader); + void render(); + + void saveState(); + void restoreState(); + IDirect3DStateBlock9 *mSavedStateBlock; + IDirect3DSurface9 *mSavedRenderTarget; + IDirect3DSurface9 *mSavedDepthStencil; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_BLIT9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp new file mode 100644 index 0000000000..dbf875134b --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp @@ -0,0 +1,141 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Buffer9.cpp Defines the Buffer9 class. + +#include "libANGLE/renderer/d3d/d3d9/Buffer9.h" + +#include "libANGLE/Context.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ + +Buffer9::Buffer9(const gl::BufferState &state, Renderer9 *renderer) + : BufferD3D(state, renderer), mSize(0) +{} + +Buffer9::~Buffer9() +{ + mSize = 0; +} + +size_t Buffer9::getSize() const +{ + return mSize; +} + +bool Buffer9::supportsDirectBinding() const +{ + return false; +} + +angle::Result Buffer9::setData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + gl::BufferUsage usage) +{ + if (size > mMemory.size()) + { + ANGLE_CHECK_GL_ALLOC(GetImplAs<Context9>(context), mMemory.resize(size)); + } + + mSize = size; + if (data && size > 0) + { + memcpy(mMemory.data(), data, size); + } + + updateD3DBufferUsage(context, usage); + + invalidateStaticData(context); + + return angle::Result::Continue; +} + +angle::Result Buffer9::getData(const gl::Context *context, const uint8_t **outData) +{ + if (mMemory.empty()) + { + *outData = nullptr; + } + else + { + *outData = mMemory.data(); + } + return angle::Result::Continue; +} + +angle::Result Buffer9::setSubData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + size_t offset) +{ + if (offset + size > mMemory.size()) + { + ANGLE_CHECK_GL_ALLOC(GetImplAs<Context9>(context), mMemory.resize(size + offset)); + } + + mSize = std::max(mSize, offset + size); + if (data && size > 0) + { + memcpy(mMemory.data() + offset, data, size); + } + + invalidateStaticData(context); + + return angle::Result::Continue; +} + +angle::Result Buffer9::copySubData(const gl::Context *context, + BufferImpl *source, + GLintptr sourceOffset, + GLintptr destOffset, + GLsizeiptr size) +{ + // Note: this method is currently unreachable + Buffer9 *sourceBuffer = GetAs<Buffer9>(source); + ASSERT(sourceBuffer); + + memcpy(mMemory.data() + destOffset, sourceBuffer->mMemory.data() + sourceOffset, size); + + invalidateStaticData(context); + + return angle::Result::Continue; +} + +// We do not support buffer mapping in D3D9 +angle::Result Buffer9::map(const gl::Context *context, GLenum access, void **mapPtr) +{ + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); + return angle::Result::Stop; +} + +angle::Result Buffer9::mapRange(const gl::Context *context, + size_t offset, + size_t length, + GLbitfield access, + void **mapPtr) +{ + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); + return angle::Result::Stop; +} + +angle::Result Buffer9::unmap(const gl::Context *context, GLboolean *result) +{ + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); + return angle::Result::Stop; +} + +angle::Result Buffer9::markTransformFeedbackUsage(const gl::Context *context) +{ + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); + return angle::Result::Stop; +} + +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Buffer9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Buffer9.h new file mode 100644 index 0000000000..dad120d75b --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Buffer9.h @@ -0,0 +1,63 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Buffer9.h: Defines the rx::Buffer9 class which implements rx::BufferImpl via rx::BufferD3D. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_BUFFER9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_BUFFER9_H_ + +#include "common/MemoryBuffer.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" + +namespace rx +{ +class Renderer9; + +class Buffer9 : public BufferD3D +{ + public: + Buffer9(const gl::BufferState &state, Renderer9 *renderer); + ~Buffer9() override; + + // BufferD3D implementation + size_t getSize() const override; + bool supportsDirectBinding() const override; + angle::Result getData(const gl::Context *context, const uint8_t **outData) override; + + // BufferImpl implementation + angle::Result setData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + gl::BufferUsage usage) override; + angle::Result setSubData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + size_t offset) override; + angle::Result copySubData(const gl::Context *context, + BufferImpl *source, + GLintptr sourceOffset, + GLintptr destOffset, + GLsizeiptr size) override; + angle::Result map(const gl::Context *context, GLenum access, void **mapPtr) override; + angle::Result mapRange(const gl::Context *context, + size_t offset, + size_t length, + GLbitfield access, + void **mapPtr) override; + angle::Result unmap(const gl::Context *context, GLboolean *result) override; + angle::Result markTransformFeedbackUsage(const gl::Context *context) override; + + private: + angle::MemoryBuffer mMemory; + size_t mSize; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_BUFFER9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Context9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Context9.cpp new file mode 100644 index 0000000000..26d28e67e3 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Context9.cpp @@ -0,0 +1,369 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Context9: +// D3D9-specific functionality associated with a GL Context. +// + +#include "libANGLE/renderer/d3d/d3d9/Context9.h" + +#include "common/string_utils.h" +#include "libANGLE/renderer/d3d/CompilerD3D.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" +#include "libANGLE/renderer/d3d/RenderbufferD3D.h" +#include "libANGLE/renderer/d3d/SamplerD3D.h" +#include "libANGLE/renderer/d3d/ShaderD3D.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/d3d9/Buffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Fence9.h" +#include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Query9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/StateManager9.h" +#include "libANGLE/renderer/d3d/d3d9/VertexArray9.h" + +namespace rx +{ + +Context9::Context9(const gl::State &state, gl::ErrorSet *errorSet, Renderer9 *renderer) + : ContextD3D(state, errorSet), mRenderer(renderer) +{} + +Context9::~Context9() {} + +angle::Result Context9::initialize() +{ + return angle::Result::Continue; +} + +void Context9::onDestroy(const gl::Context *context) +{ + mIncompleteTextures.onDestroy(context); +} + +CompilerImpl *Context9::createCompiler() +{ + return new CompilerD3D(SH_HLSL_3_0_OUTPUT); +} + +ShaderImpl *Context9::createShader(const gl::ShaderState &data) +{ + return new ShaderD3D(data, mRenderer->getFeatures(), mRenderer->getNativeExtensions()); +} + +ProgramImpl *Context9::createProgram(const gl::ProgramState &data) +{ + return new ProgramD3D(data, mRenderer); +} + +FramebufferImpl *Context9::createFramebuffer(const gl::FramebufferState &data) +{ + return new Framebuffer9(data, mRenderer); +} + +TextureImpl *Context9::createTexture(const gl::TextureState &state) +{ + switch (state.getType()) + { + case gl::TextureType::_2D: + return new TextureD3D_2D(state, mRenderer); + case gl::TextureType::CubeMap: + return new TextureD3D_Cube(state, mRenderer); + case gl::TextureType::External: + return new TextureD3D_External(state, mRenderer); + default: + UNREACHABLE(); + } + return nullptr; +} + +RenderbufferImpl *Context9::createRenderbuffer(const gl::RenderbufferState &state) +{ + return new RenderbufferD3D(state, mRenderer); +} + +BufferImpl *Context9::createBuffer(const gl::BufferState &state) +{ + return new Buffer9(state, mRenderer); +} + +VertexArrayImpl *Context9::createVertexArray(const gl::VertexArrayState &data) +{ + return new VertexArray9(data); +} + +QueryImpl *Context9::createQuery(gl::QueryType type) +{ + return new Query9(mRenderer, type); +} + +FenceNVImpl *Context9::createFenceNV() +{ + return new FenceNV9(mRenderer); +} + +SyncImpl *Context9::createSync() +{ + // D3D9 doesn't support ES 3.0 and its sync objects. + UNREACHABLE(); + return nullptr; +} + +TransformFeedbackImpl *Context9::createTransformFeedback(const gl::TransformFeedbackState &state) +{ + UNREACHABLE(); + return nullptr; +} + +SamplerImpl *Context9::createSampler(const gl::SamplerState &state) +{ + return new SamplerD3D(state); +} + +ProgramPipelineImpl *Context9::createProgramPipeline(const gl::ProgramPipelineState &data) +{ + UNREACHABLE(); + return nullptr; +} + +std::vector<PathImpl *> Context9::createPaths(GLsizei) +{ + return std::vector<PathImpl *>(); +} + +MemoryObjectImpl *Context9::createMemoryObject() +{ + UNREACHABLE(); + return nullptr; +} + +SemaphoreImpl *Context9::createSemaphore() +{ + UNREACHABLE(); + return nullptr; +} + +angle::Result Context9::flush(const gl::Context *context) +{ + return mRenderer->flush(context); +} + +angle::Result Context9::finish(const gl::Context *context) +{ + return mRenderer->finish(context); +} + +angle::Result Context9::drawArrays(const gl::Context *context, + gl::PrimitiveMode mode, + GLint first, + GLsizei count) +{ + return mRenderer->genericDrawArrays(context, mode, first, count, 0); +} + +angle::Result Context9::drawArraysInstanced(const gl::Context *context, + gl::PrimitiveMode mode, + GLint first, + GLsizei count, + GLsizei instanceCount) +{ + return mRenderer->genericDrawArrays(context, mode, first, count, instanceCount); +} + +angle::Result Context9::drawElements(const gl::Context *context, + gl::PrimitiveMode mode, + GLsizei count, + gl::DrawElementsType type, + const void *indices) +{ + return mRenderer->genericDrawElements(context, mode, count, type, indices, 0); +} + +angle::Result Context9::drawElementsInstanced(const gl::Context *context, + gl::PrimitiveMode mode, + GLsizei count, + gl::DrawElementsType type, + const void *indices, + GLsizei instances) +{ + return mRenderer->genericDrawElements(context, mode, count, type, indices, instances); +} + +angle::Result Context9::drawRangeElements(const gl::Context *context, + gl::PrimitiveMode mode, + GLuint start, + GLuint end, + GLsizei count, + gl::DrawElementsType type, + const void *indices) +{ + return mRenderer->genericDrawElements(context, mode, count, type, indices, 0); +} + +angle::Result Context9::drawArraysIndirect(const gl::Context *context, + gl::PrimitiveMode mode, + const void *indirect) +{ + ANGLE_HR_UNREACHABLE(this); + return angle::Result::Stop; +} + +angle::Result Context9::drawElementsIndirect(const gl::Context *context, + gl::PrimitiveMode mode, + gl::DrawElementsType type, + const void *indirect) +{ + ANGLE_HR_UNREACHABLE(this); + return angle::Result::Stop; +} + +gl::GraphicsResetStatus Context9::getResetStatus() +{ + return mRenderer->getResetStatus(); +} + +std::string Context9::getVendorString() const +{ + return mRenderer->getVendorString(); +} + +std::string Context9::getRendererDescription() const +{ + return mRenderer->getRendererDescription(); +} + +void Context9::insertEventMarker(GLsizei length, const char *marker) +{ + mRenderer->getAnnotator()->setMarker(marker); +} + +void Context9::pushGroupMarker(GLsizei length, const char *marker) +{ + mRenderer->getAnnotator()->beginEvent(marker, marker); + mMarkerStack.push(std::string(marker)); +} + +void Context9::popGroupMarker() +{ + const char *marker = nullptr; + if (!mMarkerStack.empty()) + { + marker = mMarkerStack.top().c_str(); + mMarkerStack.pop(); + mRenderer->getAnnotator()->endEvent(marker); + } +} + +void Context9::pushDebugGroup(GLenum source, GLuint id, const std::string &message) +{ + // Fall through to the EXT_debug_marker functions + pushGroupMarker(message.size(), message.c_str()); +} + +void Context9::popDebugGroup() +{ + // Fall through to the EXT_debug_marker functions + popGroupMarker(); +} + +angle::Result Context9::syncState(const gl::Context *context, + const gl::State::DirtyBits &dirtyBits, + const gl::State::DirtyBits &bitMask) +{ + mRenderer->getStateManager()->syncState(mState, dirtyBits); + return angle::Result::Continue; +} + +GLint Context9::getGPUDisjoint() +{ + return mRenderer->getGPUDisjoint(); +} + +GLint64 Context9::getTimestamp() +{ + return mRenderer->getTimestamp(); +} + +angle::Result Context9::onMakeCurrent(const gl::Context *context) +{ + mRenderer->getStateManager()->setAllDirtyBits(); + return mRenderer->ensureVertexDataManagerInitialized(context); +} + +gl::Caps Context9::getNativeCaps() const +{ + return mRenderer->getNativeCaps(); +} + +const gl::TextureCapsMap &Context9::getNativeTextureCaps() const +{ + return mRenderer->getNativeTextureCaps(); +} + +const gl::Extensions &Context9::getNativeExtensions() const +{ + return mRenderer->getNativeExtensions(); +} + +const gl::Limitations &Context9::getNativeLimitations() const +{ + return mRenderer->getNativeLimitations(); +} + +angle::Result Context9::dispatchCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) +{ + ANGLE_HR_UNREACHABLE(this); + return angle::Result::Stop; +} + +angle::Result Context9::dispatchComputeIndirect(const gl::Context *context, GLintptr indirect) +{ + ANGLE_HR_UNREACHABLE(this); + return angle::Result::Stop; +} + +angle::Result Context9::memoryBarrier(const gl::Context *context, GLbitfield barriers) +{ + ANGLE_HR_UNREACHABLE(this); + return angle::Result::Stop; +} + +angle::Result Context9::memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers) +{ + ANGLE_HR_UNREACHABLE(this); + return angle::Result::Stop; +} + +angle::Result Context9::getIncompleteTexture(const gl::Context *context, + gl::TextureType type, + gl::Texture **textureOut) +{ + return mIncompleteTextures.getIncompleteTexture(context, type, nullptr, textureOut); +} + +void Context9::handleResult(HRESULT hr, + const char *message, + const char *file, + const char *function, + unsigned int line) +{ + ASSERT(FAILED(hr)); + + if (d3d9::isDeviceLostError(hr)) + { + mRenderer->notifyDeviceLost(); + } + + GLenum glErrorCode = DefaultGLErrorCode(hr); + + std::stringstream errorStream; + errorStream << "Internal D3D9 error: " << gl::FmtHR(hr) << ": " << message; + + mErrors->handleError(glErrorCode, errorStream.str().c_str(), file, function, line); +} +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Context9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Context9.h new file mode 100644 index 0000000000..542131964c --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Context9.h @@ -0,0 +1,177 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Context9: +// D3D9-specific functionality associated with a GL Context. +// + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_CONTEXT9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_CONTEXT9_H_ + +#include <stack> +#include "libANGLE/renderer/d3d/ContextD3D.h" + +namespace rx +{ +class Renderer9; + +class Context9 : public ContextD3D +{ + public: + Context9(const gl::State &state, gl::ErrorSet *errorSet, Renderer9 *renderer); + ~Context9() override; + + angle::Result initialize() override; + void onDestroy(const gl::Context *context) override; + + // Shader creation + CompilerImpl *createCompiler() override; + ShaderImpl *createShader(const gl::ShaderState &data) override; + ProgramImpl *createProgram(const gl::ProgramState &data) override; + + // Framebuffer creation + FramebufferImpl *createFramebuffer(const gl::FramebufferState &data) override; + + // Texture creation + TextureImpl *createTexture(const gl::TextureState &state) override; + + // Renderbuffer creation + RenderbufferImpl *createRenderbuffer(const gl::RenderbufferState &state) override; + + // Buffer creation + BufferImpl *createBuffer(const gl::BufferState &state) override; + + // Vertex Array creation + VertexArrayImpl *createVertexArray(const gl::VertexArrayState &data) override; + + // Query and Fence creation + QueryImpl *createQuery(gl::QueryType type) override; + FenceNVImpl *createFenceNV() override; + SyncImpl *createSync() override; + + // Transform Feedback creation + TransformFeedbackImpl *createTransformFeedback( + const gl::TransformFeedbackState &state) override; + + // Sampler object creation + SamplerImpl *createSampler(const gl::SamplerState &state) override; + + // Program Pipeline object creation + ProgramPipelineImpl *createProgramPipeline(const gl::ProgramPipelineState &data) override; + + // Path object creation + std::vector<PathImpl *> createPaths(GLsizei) override; + + // Memory object creation. + MemoryObjectImpl *createMemoryObject() override; + + // Semaphore creation. + SemaphoreImpl *createSemaphore() override; + + // Flush and finish. + angle::Result flush(const gl::Context *context) override; + angle::Result finish(const gl::Context *context) override; + + // Drawing methods. + angle::Result drawArrays(const gl::Context *context, + gl::PrimitiveMode mode, + GLint first, + GLsizei count) override; + angle::Result drawArraysInstanced(const gl::Context *context, + gl::PrimitiveMode mode, + GLint first, + GLsizei count, + GLsizei instanceCount) override; + + angle::Result drawElements(const gl::Context *context, + gl::PrimitiveMode mode, + GLsizei count, + gl::DrawElementsType type, + const void *indices) override; + angle::Result drawElementsInstanced(const gl::Context *context, + gl::PrimitiveMode mode, + GLsizei count, + gl::DrawElementsType type, + const void *indices, + GLsizei instances) override; + angle::Result drawRangeElements(const gl::Context *context, + gl::PrimitiveMode mode, + GLuint start, + GLuint end, + GLsizei count, + gl::DrawElementsType type, + const void *indices) override; + angle::Result drawArraysIndirect(const gl::Context *context, + gl::PrimitiveMode mode, + const void *indirect) override; + angle::Result drawElementsIndirect(const gl::Context *context, + gl::PrimitiveMode mode, + gl::DrawElementsType type, + const void *indirect) override; + + // Device loss + gl::GraphicsResetStatus getResetStatus() override; + + // Vendor and description strings. + std::string getVendorString() const override; + std::string getRendererDescription() const override; + + // EXT_debug_marker + void insertEventMarker(GLsizei length, const char *marker) override; + void pushGroupMarker(GLsizei length, const char *marker) override; + void popGroupMarker() override; + + // KHR_debug + void pushDebugGroup(GLenum source, GLuint id, const std::string &message) override; + void popDebugGroup() override; + + // State sync with dirty bits. + angle::Result syncState(const gl::Context *context, + const gl::State::DirtyBits &dirtyBits, + const gl::State::DirtyBits &bitMask) override; + + // Disjoint timer queries + GLint getGPUDisjoint() override; + GLint64 getTimestamp() override; + + // Context switching + angle::Result onMakeCurrent(const gl::Context *context) override; + + // Caps queries + gl::Caps getNativeCaps() const override; + const gl::TextureCapsMap &getNativeTextureCaps() const override; + const gl::Extensions &getNativeExtensions() const override; + const gl::Limitations &getNativeLimitations() const override; + + angle::Result dispatchCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) override; + angle::Result dispatchComputeIndirect(const gl::Context *context, GLintptr indirect) override; + + angle::Result memoryBarrier(const gl::Context *context, GLbitfield barriers) override; + angle::Result memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers) override; + + Renderer9 *getRenderer() const { return mRenderer; } + + angle::Result getIncompleteTexture(const gl::Context *context, + gl::TextureType type, + gl::Texture **textureOut); + + void handleResult(HRESULT hr, + const char *message, + const char *file, + const char *function, + unsigned int line) override; + + private: + Renderer9 *mRenderer; + IncompleteTextureSet mIncompleteTextures; + std::stack<std::string> mMarkerStack; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_CONTEXT9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp new file mode 100644 index 0000000000..18034b6b3c --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp @@ -0,0 +1,43 @@ +// +// Copyright 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// DebugAnnotator9.h: D3D9 helpers for adding trace annotations. +// + +#include "libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h" + +#include "common/platform.h" + +namespace rx +{ + +void DebugAnnotator9::beginEvent(const char *eventName, const char *eventMessage) +{ + angle::LoggingAnnotator::beginEvent(eventName, eventMessage); + std::mbstate_t state = std::mbstate_t(); + std::mbsrtowcs(mWCharMessage, &eventMessage, kMaxMessageLength, &state); + D3DPERF_BeginEvent(0, mWCharMessage); +} + +void DebugAnnotator9::endEvent(const char *eventName) +{ + angle::LoggingAnnotator::endEvent(eventName); + D3DPERF_EndEvent(); +} + +void DebugAnnotator9::setMarker(const char *markerName) +{ + angle::LoggingAnnotator::setMarker(markerName); + std::mbstate_t state = std::mbstate_t(); + std::mbsrtowcs(mWCharMessage, &markerName, kMaxMessageLength, &state); + D3DPERF_SetMarker(0, mWCharMessage); +} + +bool DebugAnnotator9::getStatus() +{ + return !!D3DPERF_GetStatus(); +} + +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h new file mode 100644 index 0000000000..4aa23a6e33 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h @@ -0,0 +1,33 @@ +// +// Copyright 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// DebugAnnotator9.h: D3D9 helpers for adding trace annotations. +// + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_DEBUGANNOTATOR9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_DEBUGANNOTATOR9_H_ + +#include "libANGLE/LoggingAnnotator.h" + +namespace rx +{ + +class DebugAnnotator9 : public angle::LoggingAnnotator +{ + public: + DebugAnnotator9() {} + void beginEvent(const char *eventName, const char *eventMessage) override; + void endEvent(const char *eventName) override; + void setMarker(const char *markerName) override; + bool getStatus() override; + + private: + static constexpr size_t kMaxMessageLength = 256; + wchar_t mWCharMessage[kMaxMessageLength]; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_DEBUGANNOTATOR9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp new file mode 100644 index 0000000000..0113b62471 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp @@ -0,0 +1,73 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Fence9.cpp: Defines the rx::FenceNV9 class. + +#include "libANGLE/renderer/d3d/d3d9/Fence9.h" + +#include "libANGLE/Context.h" +#include "libANGLE/renderer/d3d/d3d9/Context9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" + +namespace rx +{ + +FenceNV9::FenceNV9(Renderer9 *renderer) : FenceNVImpl(), mRenderer(renderer), mQuery(nullptr) {} + +FenceNV9::~FenceNV9() +{ + SafeRelease(mQuery); +} + +angle::Result FenceNV9::set(const gl::Context *context, GLenum condition) +{ + if (!mQuery) + { + ANGLE_TRY(mRenderer->allocateEventQuery(context, &mQuery)); + } + + HRESULT result = mQuery->Issue(D3DISSUE_END); + if (FAILED(result)) + { + SafeRelease(mQuery); + } + ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to end event query"); + return angle::Result::Continue; +} + +angle::Result FenceNV9::test(const gl::Context *context, GLboolean *outFinished) +{ + return testHelper(GetImplAs<Context9>(context), true, outFinished); +} + +angle::Result FenceNV9::finish(const gl::Context *context) +{ + GLboolean finished = GL_FALSE; + while (finished != GL_TRUE) + { + ANGLE_TRY(testHelper(GetImplAs<Context9>(context), true, &finished)); + Sleep(0); + } + + return angle::Result::Continue; +} + +angle::Result FenceNV9::testHelper(Context9 *context9, + bool flushCommandBuffer, + GLboolean *outFinished) +{ + ASSERT(mQuery); + + DWORD getDataFlags = (flushCommandBuffer ? D3DGETDATA_FLUSH : 0); + HRESULT result = mQuery->GetData(nullptr, 0, getDataFlags); + ANGLE_TRY_HR(context9, result, "Failed to get query data"); + ASSERT(result == S_OK || result == S_FALSE); + *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE); + return angle::Result::Continue; +} + +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Fence9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Fence9.h new file mode 100644 index 0000000000..9237301744 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Fence9.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Fence9.h: Defines the rx::FenceNV9 class which implements rx::FenceNVImpl. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_FENCE9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_FENCE9_H_ + +#include "libANGLE/renderer/FenceNVImpl.h" +#include "libANGLE/renderer/SyncImpl.h" + +namespace rx +{ +class Context9; +class Renderer9; + +class FenceNV9 : public FenceNVImpl +{ + public: + explicit FenceNV9(Renderer9 *renderer); + ~FenceNV9() override; + + angle::Result set(const gl::Context *context, GLenum condition) override; + angle::Result test(const gl::Context *context, GLboolean *outFinished) override; + angle::Result finish(const gl::Context *context) override; + + private: + angle::Result testHelper(Context9 *context9, bool flushCommandBuffer, GLboolean *outFinished); + + Renderer9 *mRenderer; + IDirect3DQuery9 *mQuery; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_FENCE9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp new file mode 100644 index 0000000000..a982a94d28 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp @@ -0,0 +1,408 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Framebuffer9.cpp: Implements the Framebuffer9 class. + +#include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h" + +#include "libANGLE/Context.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Texture.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/ContextImpl.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/renderer_utils.h" + +namespace rx +{ +Framebuffer9::Framebuffer9(const gl::FramebufferState &data, Renderer9 *renderer) + : FramebufferD3D(data, renderer), mRenderer(renderer) +{ + ASSERT(mRenderer != nullptr); +} + +Framebuffer9::~Framebuffer9() {} + +angle::Result Framebuffer9::discard(const gl::Context *context, + size_t count, + const GLenum *attachments) +{ + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); + return angle::Result::Stop; +} + +angle::Result Framebuffer9::invalidate(const gl::Context *context, + size_t count, + const GLenum *attachments) +{ + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); + return angle::Result::Stop; +} + +angle::Result Framebuffer9::invalidateSub(const gl::Context *context, + size_t count, + const GLenum *attachments, + const gl::Rectangle &area) +{ + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); + return angle::Result::Stop; +} + +angle::Result Framebuffer9::clearImpl(const gl::Context *context, + const ClearParameters &clearParams) +{ + ANGLE_TRY(mRenderer->applyRenderTarget(context, mRenderTargetCache.getColors()[0], + mRenderTargetCache.getDepthStencil())); + + const gl::State &glState = context->getState(); + float nearZ = glState.getNearPlane(); + float farZ = glState.getFarPlane(); + mRenderer->setViewport(glState.getViewport(), nearZ, farZ, gl::PrimitiveMode::Triangles, + glState.getRasterizerState().frontFace, true); + + mRenderer->setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled()); + + mRenderer->clear(clearParams, mRenderTargetCache.getColors()[0], + mRenderTargetCache.getDepthStencil()); + return angle::Result::Continue; +} + +angle::Result Framebuffer9::readPixelsImpl(const gl::Context *context, + const gl::Rectangle &area, + GLenum format, + GLenum type, + size_t outputPitch, + const gl::PixelPackState &pack, + uint8_t *pixels) +{ + const gl::FramebufferAttachment *colorbuffer = mState.getColorAttachment(0); + ASSERT(colorbuffer); + + RenderTarget9 *renderTarget = nullptr; + ANGLE_TRY(colorbuffer->getRenderTarget(context, &renderTarget)); + ASSERT(renderTarget); + + IDirect3DSurface9 *surface = renderTarget->getSurface(); + ASSERT(surface); + + D3DSURFACE_DESC desc; + surface->GetDesc(&desc); + + Context9 *context9 = GetImplAs<Context9>(context); + + if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) + { + UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render + // target + SafeRelease(surface); + ANGLE_TRY_HR(context9, E_OUTOFMEMORY, + "ReadPixels is unimplemented for multisampled framebuffer attachments."); + } + + IDirect3DDevice9 *device = mRenderer->getDevice(); + ASSERT(device); + + HRESULT result; + IDirect3DSurface9 *systemSurface = nullptr; + bool directToPixels = + !pack.reverseRowOrder && pack.alignment <= 4 && mRenderer->getShareHandleSupport() && + area.x == 0 && area.y == 0 && static_cast<UINT>(area.width) == desc.Width && + static_cast<UINT>(area.height) == desc.Height && desc.Format == D3DFMT_A8R8G8B8 && + format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE; + if (directToPixels) + { + // Use the pixels ptr as a shared handle to write directly into client's memory + result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &systemSurface, + reinterpret_cast<void **>(&pixels)); + if (FAILED(result)) + { + // Try again without the shared handle + directToPixels = false; + } + } + + if (!directToPixels) + { + result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &systemSurface, nullptr); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + SafeRelease(surface); + ANGLE_TRY_HR(context9, E_OUTOFMEMORY, + "Failed to allocate internal texture for ReadPixels."); + } + } + + result = device->GetRenderTargetData(surface, systemSurface); + SafeRelease(surface); + + if (FAILED(result)) + { + SafeRelease(systemSurface); + + // It turns out that D3D will sometimes produce more error + // codes than those documented. + if (d3d9::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + } + else + { + UNREACHABLE(); + } + + ANGLE_TRY_HR(context9, E_OUTOFMEMORY, "Failed to read internal render target data."); + } + + if (directToPixels) + { + SafeRelease(systemSurface); + return angle::Result::Continue; + } + + RECT rect; + rect.left = gl::clamp(area.x, 0L, static_cast<LONG>(desc.Width)); + rect.top = gl::clamp(area.y, 0L, static_cast<LONG>(desc.Height)); + rect.right = gl::clamp(area.x + area.width, 0L, static_cast<LONG>(desc.Width)); + rect.bottom = gl::clamp(area.y + area.height, 0L, static_cast<LONG>(desc.Height)); + + D3DLOCKED_RECT lock; + result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY); + + if (FAILED(result)) + { + UNREACHABLE(); + SafeRelease(systemSurface); + + ANGLE_TRY_HR(context9, E_OUTOFMEMORY, "Failed to lock internal render target."); + } + + uint8_t *source = static_cast<uint8_t *>(lock.pBits); + int inputPitch = lock.Pitch; + + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); + + gl::FormatType formatType(format, type); + + PackPixelsParams packParams; + packParams.area.x = rect.left; + packParams.area.y = rect.top; + packParams.area.width = rect.right - rect.left; + packParams.area.height = rect.bottom - rect.top; + packParams.destFormat = &GetFormatFromFormatType(format, type); + packParams.outputPitch = static_cast<GLuint>(outputPitch); + packParams.reverseRowOrder = pack.reverseRowOrder; + + PackPixels(packParams, d3dFormatInfo.info(), inputPitch, source, pixels); + + systemSurface->UnlockRect(); + SafeRelease(systemSurface); + + return angle::Result::Continue; +} + +angle::Result Framebuffer9::blitImpl(const gl::Context *context, + const gl::Rectangle &sourceArea, + const gl::Rectangle &destArea, + const gl::Rectangle *scissor, + bool blitRenderTarget, + bool blitDepth, + bool blitStencil, + GLenum filter, + const gl::Framebuffer *sourceFramebuffer) +{ + ASSERT(filter == GL_NEAREST); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + ASSERT(device); + + mRenderer->endScene(); + + Context9 *context9 = GetImplAs<Context9>(context); + + if (blitRenderTarget) + { + const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getColorAttachment(0); + ASSERT(readBuffer); + + RenderTarget9 *readRenderTarget = nullptr; + ANGLE_TRY(readBuffer->getRenderTarget(context, &readRenderTarget)); + ASSERT(readRenderTarget); + + const gl::FramebufferAttachment *drawBuffer = mState.getColorAttachment(0); + ASSERT(drawBuffer); + + RenderTarget9 *drawRenderTarget = nullptr; + ANGLE_TRY(drawBuffer->getRenderTarget(context, &drawRenderTarget)); + ASSERT(drawRenderTarget); + + // The getSurface calls do an AddRef so save them until after no errors are possible + IDirect3DSurface9 *readSurface = readRenderTarget->getSurface(); + ASSERT(readSurface); + + IDirect3DSurface9 *drawSurface = drawRenderTarget->getSurface(); + ASSERT(drawSurface); + + gl::Extents srcSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); + gl::Extents dstSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); + + RECT srcRect; + srcRect.left = sourceArea.x; + srcRect.right = sourceArea.x + sourceArea.width; + srcRect.top = sourceArea.y; + srcRect.bottom = sourceArea.y + sourceArea.height; + + RECT dstRect; + dstRect.left = destArea.x; + dstRect.right = destArea.x + destArea.width; + dstRect.top = destArea.y; + dstRect.bottom = destArea.y + destArea.height; + + // Clip the rectangles to the scissor rectangle + if (scissor) + { + if (dstRect.left < scissor->x) + { + srcRect.left += (scissor->x - dstRect.left); + dstRect.left = scissor->x; + } + if (dstRect.top < scissor->y) + { + srcRect.top += (scissor->y - dstRect.top); + dstRect.top = scissor->y; + } + if (dstRect.right > scissor->x + scissor->width) + { + srcRect.right -= (dstRect.right - (scissor->x + scissor->width)); + dstRect.right = scissor->x + scissor->width; + } + if (dstRect.bottom > scissor->y + scissor->height) + { + srcRect.bottom -= (dstRect.bottom - (scissor->y + scissor->height)); + dstRect.bottom = scissor->y + scissor->height; + } + } + + // Clip the rectangles to the destination size + if (dstRect.left < 0) + { + srcRect.left += -dstRect.left; + dstRect.left = 0; + } + if (dstRect.right > dstSize.width) + { + srcRect.right -= (dstRect.right - dstSize.width); + dstRect.right = dstSize.width; + } + if (dstRect.top < 0) + { + srcRect.top += -dstRect.top; + dstRect.top = 0; + } + if (dstRect.bottom > dstSize.height) + { + srcRect.bottom -= (dstRect.bottom - dstSize.height); + dstRect.bottom = dstSize.height; + } + + // Clip the rectangles to the source size + if (srcRect.left < 0) + { + dstRect.left += -srcRect.left; + srcRect.left = 0; + } + if (srcRect.right > srcSize.width) + { + dstRect.right -= (srcRect.right - srcSize.width); + srcRect.right = srcSize.width; + } + if (srcRect.top < 0) + { + dstRect.top += -srcRect.top; + srcRect.top = 0; + } + if (srcRect.bottom > srcSize.height) + { + dstRect.bottom -= (srcRect.bottom - srcSize.height); + srcRect.bottom = srcSize.height; + } + + HRESULT result = + device->StretchRect(readSurface, &srcRect, drawSurface, &dstRect, D3DTEXF_NONE); + + SafeRelease(readSurface); + SafeRelease(drawSurface); + + ANGLE_TRY_HR(context9, result, "Internal blit failed."); + } + + if (blitDepth || blitStencil) + { + const gl::FramebufferAttachment *readBuffer = + sourceFramebuffer->getDepthOrStencilAttachment(); + ASSERT(readBuffer); + + RenderTarget9 *readDepthStencil = nullptr; + ANGLE_TRY(readBuffer->getRenderTarget(context, &readDepthStencil)); + ASSERT(readDepthStencil); + + const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment(); + ASSERT(drawBuffer); + + RenderTarget9 *drawDepthStencil = nullptr; + ANGLE_TRY(drawBuffer->getRenderTarget(context, &drawDepthStencil)); + ASSERT(drawDepthStencil); + + // The getSurface calls do an AddRef so save them until after no errors are possible + IDirect3DSurface9 *readSurface = readDepthStencil->getSurface(); + ASSERT(readDepthStencil); + + IDirect3DSurface9 *drawSurface = drawDepthStencil->getSurface(); + ASSERT(drawDepthStencil); + + HRESULT result = + device->StretchRect(readSurface, nullptr, drawSurface, nullptr, D3DTEXF_NONE); + + SafeRelease(readSurface); + SafeRelease(drawSurface); + + ANGLE_TRY_HR(context9, result, "Internal blit failed."); + } + + return angle::Result::Continue; +} + +GLenum Framebuffer9::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const +{ + RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTarget); + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(renderTarget9->getD3DFormat()); + return d3dFormatInfo.info().glInternalFormat; +} + +angle::Result Framebuffer9::getSamplePosition(const gl::Context *context, + size_t index, + GLfloat *xy) const +{ + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); + return angle::Result::Stop; +} + +angle::Result Framebuffer9::syncState(const gl::Context *context, + const gl::Framebuffer::DirtyBits &dirtyBits) +{ + ANGLE_TRY(FramebufferD3D::syncState(context, dirtyBits)); + ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits)); + return angle::Result::Continue; +} +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h new file mode 100644 index 0000000000..d9c4d7b75d --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h @@ -0,0 +1,85 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Framebuffer9.h: Defines the Framebuffer9 class. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_FRAMBUFFER9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_FRAMBUFFER9_H_ + +#include "libANGLE/renderer/RenderTargetCache.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" + +namespace rx +{ +class Renderer9; + +class Framebuffer9 : public FramebufferD3D +{ + public: + Framebuffer9(const gl::FramebufferState &data, Renderer9 *renderer); + ~Framebuffer9() override; + + angle::Result discard(const gl::Context *context, + size_t count, + const GLenum *attachments) override; + angle::Result invalidate(const gl::Context *context, + size_t count, + const GLenum *attachments) override; + angle::Result invalidateSub(const gl::Context *context, + size_t count, + const GLenum *attachments, + const gl::Rectangle &area) override; + + angle::Result getSamplePosition(const gl::Context *context, + size_t index, + GLfloat *xy) const override; + + angle::Result syncState(const gl::Context *context, + const gl::Framebuffer::DirtyBits &dirtyBits) override; + + const gl::AttachmentArray<RenderTarget9 *> &getCachedColorRenderTargets() const + { + return mRenderTargetCache.getColors(); + } + + const RenderTarget9 *getCachedDepthStencilRenderTarget() const + { + return mRenderTargetCache.getDepthStencil(); + } + + private: + angle::Result clearImpl(const gl::Context *context, + const ClearParameters &clearParams) override; + + angle::Result readPixelsImpl(const gl::Context *context, + const gl::Rectangle &area, + GLenum format, + GLenum type, + size_t outputPitch, + const gl::PixelPackState &pack, + uint8_t *pixels) override; + + angle::Result blitImpl(const gl::Context *context, + const gl::Rectangle &sourceArea, + const gl::Rectangle &destArea, + const gl::Rectangle *scissor, + bool blitRenderTarget, + bool blitDepth, + bool blitStencil, + GLenum filter, + const gl::Framebuffer *sourceFramebuffer) override; + + GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const override; + + Renderer9 *const mRenderer; + + RenderTargetCache<RenderTarget9> mRenderTargetCache; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_FRAMBUFFER9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Image9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Image9.cpp new file mode 100644 index 0000000000..0f56463961 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Image9.cpp @@ -0,0 +1,792 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Image9.cpp: Implements the rx::Image9 class, which acts as the interface to +// the actual underlying surfaces of a Texture. + +#include "libANGLE/renderer/d3d/d3d9/Image9.h" + +#include "common/utilities.h" +#include "libANGLE/Context.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/copyvertex.h" +#include "libANGLE/renderer/d3d/d3d9/Context9.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" + +namespace rx +{ + +Image9::Image9(Renderer9 *renderer) +{ + mSurface = nullptr; + mRenderer = nullptr; + + mD3DPool = D3DPOOL_SYSTEMMEM; + mD3DFormat = D3DFMT_UNKNOWN; + + mRenderer = renderer; +} + +Image9::~Image9() +{ + SafeRelease(mSurface); +} + +// static +angle::Result Image9::GenerateMip(Context9 *context9, + IDirect3DSurface9 *destSurface, + IDirect3DSurface9 *sourceSurface) +{ + D3DSURFACE_DESC destDesc; + HRESULT result = destSurface->GetDesc(&destDesc); + ASSERT(SUCCEEDED(result)); + ANGLE_TRY_HR(context9, result, + "Failed to query the source surface description for mipmap generation"); + + D3DSURFACE_DESC sourceDesc; + result = sourceSurface->GetDesc(&sourceDesc); + ASSERT(SUCCEEDED(result)); + ANGLE_TRY_HR(context9, result, + "Failed to query the destination surface description for mipmap generation"); + + ASSERT(sourceDesc.Format == destDesc.Format); + ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width); + ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height); + + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(sourceDesc.Format); + ASSERT(d3dFormatInfo.info().mipGenerationFunction != nullptr); + + D3DLOCKED_RECT sourceLocked = {0}; + result = sourceSurface->LockRect(&sourceLocked, nullptr, D3DLOCK_READONLY); + ASSERT(SUCCEEDED(result)); + ANGLE_TRY_HR(context9, result, "Failed to lock the source surface for mipmap generation"); + + D3DLOCKED_RECT destLocked = {0}; + result = destSurface->LockRect(&destLocked, nullptr, 0); + ASSERT(SUCCEEDED(result)); + ANGLE_TRY_HR(context9, result, "Failed to lock the destination surface for mipmap generation"); + + const uint8_t *sourceData = static_cast<const uint8_t *>(sourceLocked.pBits); + uint8_t *destData = static_cast<uint8_t *>(destLocked.pBits); + + ASSERT(sourceData && destData); + + d3dFormatInfo.info().mipGenerationFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData, + sourceLocked.Pitch, 0, destData, destLocked.Pitch, + 0); + + destSurface->UnlockRect(); + sourceSurface->UnlockRect(); + + return angle::Result::Continue; +} + +// static +angle::Result Image9::GenerateMipmap(Context9 *context9, Image9 *dest, Image9 *source) +{ + IDirect3DSurface9 *sourceSurface = nullptr; + ANGLE_TRY(source->getSurface(context9, &sourceSurface)); + + IDirect3DSurface9 *destSurface = nullptr; + ANGLE_TRY(dest->getSurface(context9, &destSurface)); + + ANGLE_TRY(GenerateMip(context9, destSurface, sourceSurface)); + + dest->markDirty(); + + return angle::Result::Continue; +} + +// static +angle::Result Image9::CopyLockableSurfaces(Context9 *context9, + IDirect3DSurface9 *dest, + IDirect3DSurface9 *source) +{ + D3DLOCKED_RECT sourceLock = {0}; + D3DLOCKED_RECT destLock = {0}; + + HRESULT result; + + result = source->LockRect(&sourceLock, nullptr, 0); + ANGLE_TRY_HR(context9, result, "Failed to lock source surface for copy"); + + result = dest->LockRect(&destLock, nullptr, 0); + if (FAILED(result)) + { + source->UnlockRect(); + } + ANGLE_TRY_HR(context9, result, "Failed to lock destination surface for copy"); + + ASSERT(sourceLock.pBits && destLock.pBits); + + D3DSURFACE_DESC desc; + source->GetDesc(&desc); + + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); + unsigned int rows = desc.Height / d3dFormatInfo.blockHeight; + + unsigned int bytes = d3d9::ComputeBlockSize(desc.Format, desc.Width, d3dFormatInfo.blockHeight); + ASSERT(bytes <= static_cast<unsigned int>(sourceLock.Pitch) && + bytes <= static_cast<unsigned int>(destLock.Pitch)); + + for (unsigned int i = 0; i < rows; i++) + { + memcpy((char *)destLock.pBits + destLock.Pitch * i, + (char *)sourceLock.pBits + sourceLock.Pitch * i, bytes); + } + + source->UnlockRect(); + dest->UnlockRect(); + + return angle::Result::Continue; +} + +// static +angle::Result Image9::CopyImage(const gl::Context *context, + Image9 *dest, + Image9 *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) +{ + Context9 *context9 = GetImplAs<Context9>(context); + + IDirect3DSurface9 *sourceSurface = nullptr; + ANGLE_TRY(source->getSurface(context9, &sourceSurface)); + + IDirect3DSurface9 *destSurface = nullptr; + ANGLE_TRY(dest->getSurface(context9, &destSurface)); + + D3DSURFACE_DESC destDesc; + HRESULT result = destSurface->GetDesc(&destDesc); + ASSERT(SUCCEEDED(result)); + ANGLE_TRY_HR(context9, result, "Failed to query the source surface description for CopyImage"); + const d3d9::D3DFormat &destD3DFormatInfo = d3d9::GetD3DFormatInfo(destDesc.Format); + + D3DSURFACE_DESC sourceDesc; + result = sourceSurface->GetDesc(&sourceDesc); + ASSERT(SUCCEEDED(result)); + ANGLE_TRY_HR(context9, result, + "Failed to query the destination surface description for CopyImage"); + const d3d9::D3DFormat &sourceD3DFormatInfo = d3d9::GetD3DFormatInfo(sourceDesc.Format); + + D3DLOCKED_RECT sourceLocked = {0}; + result = sourceSurface->LockRect(&sourceLocked, nullptr, D3DLOCK_READONLY); + ASSERT(SUCCEEDED(result)); + ANGLE_TRY_HR(context9, result, "Failed to lock the source surface for CopyImage"); + + D3DLOCKED_RECT destLocked = {0}; + result = destSurface->LockRect(&destLocked, nullptr, 0); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + sourceSurface->UnlockRect(); + } + ANGLE_TRY_HR(context9, result, "Failed to lock the destination surface for CopyImage"); + + const uint8_t *sourceData = static_cast<const uint8_t *>(sourceLocked.pBits) + + sourceRect.x * sourceD3DFormatInfo.pixelBytes + + sourceRect.y * sourceLocked.Pitch; + uint8_t *destData = static_cast<uint8_t *>(destLocked.pBits) + + destOffset.x * destD3DFormatInfo.pixelBytes + + destOffset.y * destLocked.Pitch; + ASSERT(sourceData && destData); + + CopyImageCHROMIUM(sourceData, sourceLocked.Pitch, sourceD3DFormatInfo.pixelBytes, 0, + sourceD3DFormatInfo.info().pixelReadFunction, destData, destLocked.Pitch, + destD3DFormatInfo.pixelBytes, 0, destD3DFormatInfo.info().pixelWriteFunction, + gl::GetUnsizedFormat(dest->getInternalFormat()), + destD3DFormatInfo.info().componentType, sourceRect.width, sourceRect.height, + 1, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha); + + destSurface->UnlockRect(); + sourceSurface->UnlockRect(); + + return angle::Result::Continue; +} + +bool Image9::redefine(gl::TextureType type, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease) +{ + // 3D textures are not supported by the D3D9 backend. + ASSERT(size.depth <= 1); + + // Only 2D and cube texture are supported by the D3D9 backend. + ASSERT(type == gl::TextureType::_2D || type == gl::TextureType::CubeMap); + + if (mWidth != size.width || mHeight != size.height || mDepth != size.depth || + mInternalFormat != internalformat || forceRelease) + { + mWidth = size.width; + mHeight = size.height; + mDepth = size.depth; + mType = type; + mInternalFormat = internalformat; + + // compute the d3d format that will be used + const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(internalformat); + mD3DFormat = d3d9FormatInfo.texFormat; + mRenderable = (d3d9FormatInfo.renderFormat != D3DFMT_UNKNOWN); + + SafeRelease(mSurface); + mDirty = (d3d9FormatInfo.dataInitializerFunction != nullptr); + + return true; + } + + return false; +} + +angle::Result Image9::createSurface(Context9 *context9) +{ + if (mSurface) + { + return angle::Result::Continue; + } + + IDirect3DTexture9 *newTexture = nullptr; + IDirect3DSurface9 *newSurface = nullptr; + 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, nullptr); + + ANGLE_TRY_HR(context9, result, "Failed to create image surface"); + + newTexture->GetSurfaceLevel(levelToFetch, &newSurface); + SafeRelease(newTexture); + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); + if (d3dFormatInfo.dataInitializerFunction != nullptr) + { + 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)); + ANGLE_TRY_HR(context9, result, "Failed to lock image surface"); + + d3dFormatInfo.dataInitializerFunction( + mWidth, mHeight, 1, static_cast<uint8_t *>(lockedRect.pBits), lockedRect.Pitch, 0); + + result = newSurface->UnlockRect(); + ASSERT(SUCCEEDED(result)); + ANGLE_TRY_HR(context9, result, "Failed to unlock image surface"); + } + } + + mSurface = newSurface; + mDirty = false; + mD3DPool = poolToUse; + + return angle::Result::Continue; +} + +angle::Result Image9::lock(Context9 *context9, D3DLOCKED_RECT *lockedRect, const RECT &rect) +{ + ANGLE_TRY(createSurface(context9)); + + if (mSurface) + { + HRESULT result = mSurface->LockRect(lockedRect, &rect, 0); + ASSERT(SUCCEEDED(result)); + ANGLE_TRY_HR(context9, result, "Failed to lock image surface"); + mDirty = true; + } + + return angle::Result::Continue; +} + +void Image9::unlock() +{ + if (mSurface) + { + HRESULT result = mSurface->UnlockRect(); + ASSERT(SUCCEEDED(result)); + } +} + +D3DFORMAT Image9::getD3DFormat() const +{ + // this should only happen if the image hasn't been redefined first + // which would be a bug by the caller + ASSERT(mD3DFormat != D3DFMT_UNKNOWN); + + return mD3DFormat; +} + +bool Image9::isDirty() const +{ + // Make sure to that this image is marked as dirty even if the staging texture hasn't been + // created yet if initialization is required before use. + return (mSurface || + d3d9::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != nullptr) && + mDirty; +} + +angle::Result Image9::getSurface(Context9 *context9, IDirect3DSurface9 **outSurface) +{ + ANGLE_TRY(createSurface(context9)); + *outSurface = mSurface; + return angle::Result::Continue; +} + +angle::Result Image9::setManagedSurface2D(const gl::Context *context, + TextureStorage *storage, + int level) +{ + IDirect3DSurface9 *surface = nullptr; + TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage); + ANGLE_TRY(storage9->getSurfaceLevel(context, gl::TextureTarget::_2D, level, false, &surface)); + return setManagedSurface(GetImplAs<Context9>(context), surface); +} + +angle::Result Image9::setManagedSurfaceCube(const gl::Context *context, + TextureStorage *storage, + int face, + int level) +{ + IDirect3DSurface9 *surface = nullptr; + TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage); + ANGLE_TRY(storage9->getSurfaceLevel(context, gl::CubeFaceIndexToTextureTarget(face), level, + false, &surface)); + return setManagedSurface(GetImplAs<Context9>(context), surface); +} + +angle::Result Image9::setManagedSurface(Context9 *context9, IDirect3DSurface9 *surface) +{ + D3DSURFACE_DESC desc; + surface->GetDesc(&desc); + ASSERT(desc.Pool == D3DPOOL_MANAGED); + + if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight) + { + if (mSurface) + { + angle::Result result = CopyLockableSurfaces(context9, surface, mSurface); + SafeRelease(mSurface); + ANGLE_TRY(result); + } + + mSurface = surface; + mD3DPool = desc.Pool; + } + + return angle::Result::Continue; +} + +angle::Result Image9::copyToStorage(const gl::Context *context, + TextureStorage *storage, + const gl::ImageIndex &index, + const gl::Box ®ion) +{ + ANGLE_TRY(createSurface(GetImplAs<Context9>(context))); + + TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage); + IDirect3DSurface9 *destSurface = nullptr; + ANGLE_TRY(storage9->getSurfaceLevel(context, index.getTarget(), index.getLevelIndex(), true, + &destSurface)); + + angle::Result result = copyToSurface(GetImplAs<Context9>(context), destSurface, region); + SafeRelease(destSurface); + return result; +} + +angle::Result Image9::copyToSurface(Context9 *context9, + IDirect3DSurface9 *destSurface, + const gl::Box &area) +{ + ASSERT(area.width > 0 && area.height > 0 && area.depth == 1); + ASSERT(destSurface); + + IDirect3DSurface9 *sourceSurface = nullptr; + ANGLE_TRY(getSurface(context9, &sourceSurface)); + + ASSERT(sourceSurface && sourceSurface != destSurface); + + RECT rect; + rect.left = area.x; + rect.top = area.y; + rect.right = area.x + area.width; + rect.bottom = area.y + area.height; + + POINT point = {rect.left, rect.top}; + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + if (mD3DPool == D3DPOOL_MANAGED) + { + D3DSURFACE_DESC desc; + sourceSurface->GetDesc(&desc); + + IDirect3DSurface9 *surf = 0; + HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &surf, nullptr); + ANGLE_TRY_HR(context9, result, "Internal CreateOffscreenPlainSurface call failed"); + + auto err = CopyLockableSurfaces(context9, surf, sourceSurface); + result = device->UpdateSurface(surf, &rect, destSurface, &point); + SafeRelease(surf); + ANGLE_TRY(err); + ASSERT(SUCCEEDED(result)); + ANGLE_TRY_HR(context9, result, "Internal UpdateSurface call failed"); + } + else + { + // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools + HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point); + ASSERT(SUCCEEDED(result)); + ANGLE_TRY_HR(context9, result, "Internal UpdateSurface call failed"); + } + + return angle::Result::Continue; +} + +// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as +// format/type at input into the target pixel rectangle. +angle::Result Image9::loadData(const gl::Context *context, + const gl::Box &area, + const gl::PixelUnpackState &unpack, + GLenum type, + const void *input, + bool applySkipImages) +{ + // 3D textures are not supported by the D3D9 backend. + ASSERT(area.z == 0 && area.depth == 1); + + Context9 *context9 = GetImplAs<Context9>(context); + + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat); + GLuint inputRowPitch = 0; + ANGLE_CHECK_GL_MATH(context9, formatInfo.computeRowPitch(type, area.width, unpack.alignment, + unpack.rowLength, &inputRowPitch)); + ASSERT(!applySkipImages); + ASSERT(unpack.skipPixels == 0); + ASSERT(unpack.skipRows == 0); + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); + ASSERT(d3dFormatInfo.loadFunction != nullptr); + + RECT lockRect = {area.x, area.y, area.x + area.width, area.y + area.height}; + + D3DLOCKED_RECT locked; + ANGLE_TRY(lock(GetImplAs<Context9>(context), &locked, lockRect)); + + d3dFormatInfo.loadFunction(area.width, area.height, area.depth, + static_cast<const uint8_t *>(input), inputRowPitch, 0, + static_cast<uint8_t *>(locked.pBits), locked.Pitch, 0); + + unlock(); + + return angle::Result::Continue; +} + +angle::Result Image9::loadCompressedData(const gl::Context *context, + const gl::Box &area, + const void *input) +{ + // 3D textures are not supported by the D3D9 backend. + ASSERT(area.z == 0 && area.depth == 1); + + Context9 *context9 = GetImplAs<Context9>(context); + + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat); + GLuint inputRowPitch = 0; + ANGLE_CHECK_GL_MATH( + context9, formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0, &inputRowPitch)); + + GLuint inputDepthPitch = 0; + ANGLE_CHECK_GL_MATH( + context9, formatInfo.computeDepthPitch(area.height, 0, inputRowPitch, &inputDepthPitch)); + + const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); + + ASSERT(area.x % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockWidth == 0); + ASSERT(area.y % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockHeight == 0); + + ASSERT(d3d9FormatInfo.loadFunction != nullptr); + + RECT lockRect = {area.x, area.y, area.x + area.width, area.y + area.height}; + + D3DLOCKED_RECT locked; + ANGLE_TRY(lock(GetImplAs<Context9>(context), &locked, lockRect)); + + d3d9FormatInfo.loadFunction(area.width, area.height, area.depth, + static_cast<const uint8_t *>(input), inputRowPitch, inputDepthPitch, + static_cast<uint8_t *>(locked.pBits), locked.Pitch, 0); + + unlock(); + + return angle::Result::Continue; +} + +// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete +// textures +angle::Result Image9::copyFromRTInternal(Context9 *context9, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, + RenderTargetD3D *source) +{ + ASSERT(source); + + // ES3.0 only behaviour to copy into a 3d texture + ASSERT(destOffset.z == 0); + + RenderTarget9 *renderTarget = GetAs<RenderTarget9>(source); + + angle::ComPtr<IDirect3DSurface9> surface = renderTarget->getSurface(); + ASSERT(surface); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + angle::ComPtr<IDirect3DSurface9> renderTargetData = nullptr; + D3DSURFACE_DESC description; + surface->GetDesc(&description); + + HRESULT hr = device->CreateOffscreenPlainSurface(description.Width, description.Height, + description.Format, D3DPOOL_SYSTEMMEM, + &renderTargetData, nullptr); + + ANGLE_TRY_HR(context9, hr, "Could not create matching destination surface"); + + hr = device->GetRenderTargetData(surface.Get(), renderTargetData.Get()); + + ANGLE_TRY_HR(context9, hr, "GetRenderTargetData unexpectedly failed"); + + int width = sourceArea.width; + int height = sourceArea.height; + + RECT sourceRect = {sourceArea.x, sourceArea.y, sourceArea.x + width, sourceArea.y + height}; + RECT destRect = {destOffset.x, destOffset.y, destOffset.x + width, destOffset.y + height}; + + D3DLOCKED_RECT sourceLock = {0}; + hr = renderTargetData->LockRect(&sourceLock, &sourceRect, 0); + + ANGLE_TRY_HR(context9, hr, "Failed to lock the source surface (rectangle might be invalid)"); + + D3DLOCKED_RECT destLock = {0}; + angle::Result result = lock(context9, &destLock, destRect); + if (result == angle::Result::Stop) + { + renderTargetData->UnlockRect(); + } + ANGLE_TRY(result); + + ASSERT(destLock.pBits && sourceLock.pBits); + + unsigned char *sourcePixels = (unsigned char *)sourceLock.pBits; + unsigned char *destPixels = (unsigned char *)destLock.pBits; + + switch (description.Format) + { + case D3DFMT_X8R8G8B8: + case D3DFMT_A8R8G8B8: + switch (getD3DFormat()) + { + case D3DFMT_X8R8G8B8: + case D3DFMT_A8R8G8B8: + for (int y = 0; y < height; y++) + { + memcpy(destPixels, sourcePixels, 4 * width); + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + destPixels[x] = sourcePixels[x * 4 + 2]; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_A8L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + destPixels[x * 2 + 0] = sourcePixels[x * 4 + 2]; + destPixels[x * 2 + 1] = sourcePixels[x * 4 + 3]; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + default: + UNREACHABLE(); + } + break; + case D3DFMT_R5G6B5: + switch (getD3DFormat()) + { + case D3DFMT_X8R8G8B8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned short rgb = ((unsigned short *)sourcePixels)[x]; + unsigned char red = static_cast<unsigned char>((rgb & 0xF800) >> 8); + unsigned char green = static_cast<unsigned char>((rgb & 0x07E0) >> 3); + unsigned char blue = static_cast<unsigned char>((rgb & 0x001F) << 3); + destPixels[x + 0] = blue | (blue >> 5); + destPixels[x + 1] = green | (green >> 6); + destPixels[x + 2] = red | (red >> 5); + destPixels[x + 3] = 0xFF; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned char red = sourcePixels[x * 2 + 1] & 0xF8; + destPixels[x] = red | (red >> 5); + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + default: + UNREACHABLE(); + } + break; + case D3DFMT_A1R5G5B5: + switch (getD3DFormat()) + { + case D3DFMT_X8R8G8B8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned short argb = ((unsigned short *)sourcePixels)[x]; + unsigned char red = static_cast<unsigned char>((argb & 0x7C00) >> 7); + unsigned char green = static_cast<unsigned char>((argb & 0x03E0) >> 2); + unsigned char blue = static_cast<unsigned char>((argb & 0x001F) << 3); + destPixels[x + 0] = blue | (blue >> 5); + destPixels[x + 1] = green | (green >> 5); + destPixels[x + 2] = red | (red >> 5); + destPixels[x + 3] = 0xFF; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_A8R8G8B8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned short argb = ((unsigned short *)sourcePixels)[x]; + unsigned char red = static_cast<unsigned char>((argb & 0x7C00) >> 7); + unsigned char green = static_cast<unsigned char>((argb & 0x03E0) >> 2); + unsigned char blue = static_cast<unsigned char>((argb & 0x001F) << 3); + unsigned char alpha = (signed short)argb >> 15; + destPixels[x + 0] = blue | (blue >> 5); + destPixels[x + 1] = green | (green >> 5); + destPixels[x + 2] = red | (red >> 5); + destPixels[x + 3] = alpha; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned char red = sourcePixels[x * 2 + 1] & 0x7C; + destPixels[x] = (red << 1) | (red >> 4); + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_A8L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned char red = sourcePixels[x * 2 + 1] & 0x7C; + destPixels[x * 2 + 0] = (red << 1) | (red >> 4); + destPixels[x * 2 + 1] = (signed char)sourcePixels[x * 2 + 1] >> 7; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + default: + UNREACHABLE(); + } + break; + default: + UNREACHABLE(); + } + + unlock(); + renderTargetData->UnlockRect(); + + mDirty = true; + return angle::Result::Continue; +} + +angle::Result Image9::copyFromTexStorage(const gl::Context *context, + const gl::ImageIndex &imageIndex, + TextureStorage *source) +{ + RenderTargetD3D *renderTarget = nullptr; + ANGLE_TRY(source->getRenderTarget(context, imageIndex, &renderTarget)); + + gl::Rectangle sourceArea(0, 0, mWidth, mHeight); + return copyFromRTInternal(GetImplAs<Context9>(context), gl::Offset(), sourceArea, renderTarget); +} + +angle::Result Image9::copyFromFramebuffer(const gl::Context *context, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) +{ + const gl::FramebufferAttachment *srcAttachment = source->getReadColorAttachment(); + ASSERT(srcAttachment); + + RenderTargetD3D *renderTarget = nullptr; + ANGLE_TRY(srcAttachment->getRenderTarget(context, &renderTarget)); + ASSERT(renderTarget); + return copyFromRTInternal(GetImplAs<Context9>(context), destOffset, sourceArea, renderTarget); +} + +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Image9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Image9.h new file mode 100644 index 0000000000..81b8e9c12c --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Image9.h @@ -0,0 +1,112 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Image9.h: Defines the rx::Image9 class, which acts as the interface to +// the actual underlying surfaces of a Texture. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_IMAGE9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_IMAGE9_H_ + +#include "common/debug.h" +#include "libANGLE/renderer/d3d/ImageD3D.h" + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ +class Context9; +class Renderer9; + +class Image9 : public ImageD3D +{ + public: + Image9(Renderer9 *renderer); + ~Image9() override; + + static angle::Result GenerateMipmap(Context9 *context9, Image9 *dest, Image9 *source); + static angle::Result GenerateMip(Context9 *context9, + IDirect3DSurface9 *destSurface, + IDirect3DSurface9 *sourceSurface); + static angle::Result CopyLockableSurfaces(Context9 *context9, + IDirect3DSurface9 *dest, + IDirect3DSurface9 *source); + static angle::Result CopyImage(const gl::Context *context, + Image9 *dest, + Image9 *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha); + + bool redefine(gl::TextureType type, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease) override; + + D3DFORMAT getD3DFormat() const; + + bool isDirty() const override; + + angle::Result setManagedSurface2D(const gl::Context *context, + TextureStorage *storage, + int level) override; + angle::Result setManagedSurfaceCube(const gl::Context *context, + TextureStorage *storage, + int face, + int level) override; + angle::Result copyToStorage(const gl::Context *context, + TextureStorage *storage, + const gl::ImageIndex &index, + const gl::Box ®ion) override; + + angle::Result loadData(const gl::Context *context, + const gl::Box &area, + const gl::PixelUnpackState &unpack, + GLenum type, + const void *input, + bool applySkipImages) override; + angle::Result loadCompressedData(const gl::Context *context, + const gl::Box &area, + const void *input) override; + + angle::Result copyFromTexStorage(const gl::Context *context, + const gl::ImageIndex &imageIndex, + TextureStorage *source) override; + angle::Result copyFromFramebuffer(const gl::Context *context, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) override; + + private: + angle::Result getSurface(Context9 *context9, IDirect3DSurface9 **outSurface); + + angle::Result createSurface(Context9 *context9); + angle::Result setManagedSurface(Context9 *context9, IDirect3DSurface9 *surface); + angle::Result copyToSurface(Context9 *context9, IDirect3DSurface9 *dest, const gl::Box &area); + + angle::Result lock(Context9 *context9, D3DLOCKED_RECT *lockedRect, const RECT &rect); + void unlock(); + + angle::Result copyFromRTInternal(Context9 *context9, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, + RenderTargetD3D *source); + + Renderer9 *mRenderer; + + D3DPOOL mD3DPool; // can only be D3DPOOL_SYSTEMMEM or D3DPOOL_MANAGED since it needs to be + // lockable. + D3DFORMAT mD3DFormat; + + IDirect3DSurface9 *mSurface; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_IMAGE9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp new file mode 100644 index 0000000000..d1b1b51a64 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp @@ -0,0 +1,161 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Indexffer9.cpp: Defines the D3D9 IndexBuffer implementation. + +#include "libANGLE/renderer/d3d/d3d9/IndexBuffer9.h" + +#include "libANGLE/Context.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ + +IndexBuffer9::IndexBuffer9(Renderer9 *const renderer) : mRenderer(renderer) +{ + mIndexBuffer = nullptr; + mBufferSize = 0; + mIndexType = gl::DrawElementsType::InvalidEnum; + mDynamic = false; +} + +IndexBuffer9::~IndexBuffer9() +{ + SafeRelease(mIndexBuffer); +} + +angle::Result IndexBuffer9::initialize(const gl::Context *context, + unsigned int bufferSize, + gl::DrawElementsType indexType, + bool dynamic) +{ + SafeRelease(mIndexBuffer); + + updateSerial(); + + if (bufferSize > 0) + { + D3DFORMAT format = D3DFMT_UNKNOWN; + if (indexType == gl::DrawElementsType::UnsignedShort || + indexType == gl::DrawElementsType::UnsignedByte) + { + format = D3DFMT_INDEX16; + } + else if (indexType == gl::DrawElementsType::UnsignedInt) + { + ASSERT(mRenderer->getNativeExtensions().elementIndexUint); + format = D3DFMT_INDEX32; + } + else + UNREACHABLE(); + + DWORD usageFlags = D3DUSAGE_WRITEONLY; + if (dynamic) + { + usageFlags |= D3DUSAGE_DYNAMIC; + } + + HRESULT result = + mRenderer->createIndexBuffer(bufferSize, usageFlags, format, &mIndexBuffer); + ANGLE_TRY_HR(GetImplAs<Context9>(context), result, + "Failed to allocate internal index buffer"); + } + + mBufferSize = bufferSize; + mIndexType = indexType; + mDynamic = dynamic; + + return angle::Result::Continue; +} + +angle::Result IndexBuffer9::mapBuffer(const gl::Context *context, + unsigned int offset, + unsigned int size, + void **outMappedMemory) +{ + ASSERT(mIndexBuffer); + + DWORD lockFlags = mDynamic ? D3DLOCK_NOOVERWRITE : 0; + + void *mapPtr = nullptr; + HRESULT result = mIndexBuffer->Lock(offset, size, &mapPtr, lockFlags); + ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to lock internal index buffer"); + + *outMappedMemory = mapPtr; + return angle::Result::Continue; +} + +angle::Result IndexBuffer9::unmapBuffer(const gl::Context *context) +{ + ASSERT(mIndexBuffer); + HRESULT result = mIndexBuffer->Unlock(); + ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to unlock internal index buffer"); + + return angle::Result::Continue; +} + +gl::DrawElementsType IndexBuffer9::getIndexType() const +{ + return mIndexType; +} + +unsigned int IndexBuffer9::getBufferSize() const +{ + return mBufferSize; +} + +angle::Result IndexBuffer9::setSize(const gl::Context *context, + unsigned int bufferSize, + gl::DrawElementsType indexType) +{ + if (bufferSize > mBufferSize || indexType != mIndexType) + { + return initialize(context, bufferSize, indexType, mDynamic); + } + + return angle::Result::Continue; +} + +angle::Result IndexBuffer9::discard(const gl::Context *context) +{ + ASSERT(mIndexBuffer); + + void *dummy; + HRESULT result; + + Context9 *context9 = GetImplAs<Context9>(context); + + result = mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); + ANGLE_TRY_HR(context9, result, "Failed to lock internal index buffer"); + + result = mIndexBuffer->Unlock(); + ANGLE_TRY_HR(context9, result, "Failed to unlock internal index buffer"); + + return angle::Result::Continue; +} + +D3DFORMAT IndexBuffer9::getIndexFormat() const +{ + switch (mIndexType) + { + case gl::DrawElementsType::UnsignedByte: + return D3DFMT_INDEX16; + case gl::DrawElementsType::UnsignedShort: + return D3DFMT_INDEX16; + case gl::DrawElementsType::UnsignedInt: + return D3DFMT_INDEX32; + default: + UNREACHABLE(); + return D3DFMT_UNKNOWN; + } +} + +IDirect3DIndexBuffer9 *IndexBuffer9::getBuffer() const +{ + return mIndexBuffer; +} + +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h new file mode 100644 index 0000000000..ca7cc20ed2 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h @@ -0,0 +1,57 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Indexffer9.h: Defines the D3D9 IndexBuffer implementation. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_INDEXBUFFER9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_INDEXBUFFER9_H_ + +#include "libANGLE/renderer/d3d/IndexBuffer.h" + +namespace rx +{ +class Renderer9; + +class IndexBuffer9 : public IndexBuffer +{ + public: + explicit IndexBuffer9(Renderer9 *const renderer); + ~IndexBuffer9() override; + + angle::Result initialize(const gl::Context *context, + unsigned int bufferSize, + gl::DrawElementsType indexType, + bool dynamic) override; + + angle::Result mapBuffer(const gl::Context *context, + unsigned int offset, + unsigned int size, + void **outMappedMemory) override; + angle::Result unmapBuffer(const gl::Context *context) override; + + gl::DrawElementsType getIndexType() const override; + unsigned int getBufferSize() const override; + angle::Result setSize(const gl::Context *context, + unsigned int bufferSize, + gl::DrawElementsType indexType) override; + + angle::Result discard(const gl::Context *context) override; + + D3DFORMAT getIndexFormat() const; + IDirect3DIndexBuffer9 *getBuffer() const; + + private: + Renderer9 *const mRenderer; + + IDirect3DIndexBuffer9 *mIndexBuffer; + unsigned int mBufferSize; + gl::DrawElementsType mIndexType; + bool mDynamic; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_INDEXBUFFER9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp new file mode 100644 index 0000000000..6ee408fe8b --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp @@ -0,0 +1,37 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindow9.cpp: Defines NativeWindow9, a class for managing and +// performing operations on an EGLNativeWindowType for the D3D9 renderer. + +#include "libANGLE/renderer/d3d/d3d9/NativeWindow9.h" + +namespace rx +{ +NativeWindow9::NativeWindow9(EGLNativeWindowType window) : NativeWindowD3D(window) {} + +bool NativeWindow9::initialize() +{ + return true; +} + +bool NativeWindow9::getClientRect(LPRECT rect) const +{ + return GetClientRect(getNativeWindow(), rect) == TRUE; +} + +bool NativeWindow9::isIconic() const +{ + return IsIconic(getNativeWindow()) == TRUE; +} + +// static +bool NativeWindow9::IsValidNativeWindow(EGLNativeWindowType window) +{ + return IsWindow(window) == TRUE; +} + +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h new file mode 100644 index 0000000000..a56b08dc81 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h @@ -0,0 +1,35 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindow9.h: Defines NativeWindow9, a class for managing and +// performing operations on an EGLNativeWindowType for the D3D9 renderer. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_NATIVEWINDOW9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_NATIVEWINDOW9_H_ + +#include "common/debug.h" +#include "common/platform.h" + +#include "libANGLE/renderer/d3d/NativeWindowD3D.h" + +namespace rx +{ + +class NativeWindow9 : public NativeWindowD3D +{ + public: + explicit NativeWindow9(EGLNativeWindowType window); + + bool initialize() override; + bool getClientRect(LPRECT rect) const override; + bool isIconic() const override; + + static bool IsValidNativeWindow(EGLNativeWindowType window); +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_NATIVEWINDOW9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Query9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Query9.cpp new file mode 100644 index 0000000000..06a977ce10 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Query9.cpp @@ -0,0 +1,176 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Query9.cpp: Defines the rx::Query9 class which implements rx::QueryImpl. + +#include "libANGLE/renderer/d3d/d3d9/Query9.h" + +#include "libANGLE/Context.h" +#include "libANGLE/renderer/d3d/d3d9/Context9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" + +#include <GLES2/gl2ext.h> + +namespace rx +{ +Query9::Query9(Renderer9 *renderer, gl::QueryType type) + : QueryImpl(type), + mGetDataAttemptCount(0), + mResult(GL_FALSE), + mQueryFinished(false), + mRenderer(renderer), + mQuery(nullptr) +{} + +Query9::~Query9() +{ + SafeRelease(mQuery); +} + +angle::Result Query9::begin(const gl::Context *context) +{ + Context9 *context9 = GetImplAs<Context9>(context); + + D3DQUERYTYPE d3dQueryType = gl_d3d9::ConvertQueryType(getType()); + if (mQuery == nullptr) + { + HRESULT result = mRenderer->getDevice()->CreateQuery(d3dQueryType, &mQuery); + ANGLE_TRY_HR(context9, result, "Internal query creation failed"); + } + + if (d3dQueryType != D3DQUERYTYPE_EVENT) + { + HRESULT result = mQuery->Issue(D3DISSUE_BEGIN); + ASSERT(SUCCEEDED(result)); + ANGLE_TRY_HR(context9, result, "Failed to begin internal query"); + } + + return angle::Result::Continue; +} + +angle::Result Query9::end(const gl::Context *context) +{ + Context9 *context9 = GetImplAs<Context9>(context); + ASSERT(mQuery); + + HRESULT result = mQuery->Issue(D3DISSUE_END); + ASSERT(SUCCEEDED(result)); + ANGLE_TRY_HR(context9, result, "Failed to end internal query"); + mQueryFinished = false; + mResult = GL_FALSE; + + return angle::Result::Continue; +} + +angle::Result Query9::queryCounter(const gl::Context *context) +{ + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); +} + +template <typename T> +angle::Result Query9::getResultBase(Context9 *context9, T *params) +{ + while (!mQueryFinished) + { + ANGLE_TRY(testQuery(context9)); + + if (!mQueryFinished) + { + Sleep(0); + } + } + + ASSERT(mQueryFinished); + *params = static_cast<T>(mResult); + return angle::Result::Continue; +} + +angle::Result Query9::getResult(const gl::Context *context, GLint *params) +{ + return getResultBase(GetImplAs<Context9>(context), params); +} + +angle::Result Query9::getResult(const gl::Context *context, GLuint *params) +{ + return getResultBase(GetImplAs<Context9>(context), params); +} + +angle::Result Query9::getResult(const gl::Context *context, GLint64 *params) +{ + return getResultBase(GetImplAs<Context9>(context), params); +} + +angle::Result Query9::getResult(const gl::Context *context, GLuint64 *params) +{ + return getResultBase(GetImplAs<Context9>(context), params); +} + +angle::Result Query9::isResultAvailable(const gl::Context *context, bool *available) +{ + ANGLE_TRY(testQuery(GetImplAs<Context9>(context))); + *available = mQueryFinished; + return angle::Result::Continue; +} + +angle::Result Query9::testQuery(Context9 *context9) +{ + if (!mQueryFinished) + { + ASSERT(mQuery); + + HRESULT result = S_OK; + switch (getType()) + { + case gl::QueryType::AnySamples: + case gl::QueryType::AnySamplesConservative: + { + DWORD numPixels = 0; + result = mQuery->GetData(&numPixels, sizeof(numPixels), D3DGETDATA_FLUSH); + if (result == S_OK) + { + mQueryFinished = true; + mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + } + break; + } + + case gl::QueryType::CommandsCompleted: + { + BOOL completed = FALSE; + result = mQuery->GetData(&completed, sizeof(completed), D3DGETDATA_FLUSH); + if (result == S_OK) + { + mQueryFinished = true; + mResult = (completed == TRUE) ? GL_TRUE : GL_FALSE; + } + break; + } + + default: + UNREACHABLE(); + break; + } + + if (!mQueryFinished) + { + ANGLE_TRY_HR(context9, result, "Failed to test get query result"); + + mGetDataAttemptCount++; + bool checkDeviceLost = + (mGetDataAttemptCount % kPollingD3DDeviceLostCheckFrequency) == 0; + if (checkDeviceLost && mRenderer->testDeviceLost()) + { + ANGLE_TRY_HR(context9, D3DERR_DEVICELOST, + "Failed to test get query result, device is lost"); + } + } + } + + return angle::Result::Continue; +} + +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Query9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Query9.h new file mode 100644 index 0000000000..15e4be5bb5 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Query9.h @@ -0,0 +1,50 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Query9.h: Defines the rx::Query9 class which implements rx::QueryImpl. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_QUERY9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_QUERY9_H_ + +#include "libANGLE/renderer/QueryImpl.h" + +namespace rx +{ +class Context9; +class Renderer9; + +class Query9 : public QueryImpl +{ + public: + Query9(Renderer9 *renderer, gl::QueryType type); + ~Query9() override; + + angle::Result begin(const gl::Context *context) override; + angle::Result end(const gl::Context *context) override; + angle::Result queryCounter(const gl::Context *context) override; + angle::Result getResult(const gl::Context *context, GLint *params) override; + angle::Result getResult(const gl::Context *context, GLuint *params) override; + angle::Result getResult(const gl::Context *context, GLint64 *params) override; + angle::Result getResult(const gl::Context *context, GLuint64 *params) override; + angle::Result isResultAvailable(const gl::Context *context, bool *available) override; + + private: + angle::Result testQuery(Context9 *context9); + + template <typename T> + angle::Result getResultBase(Context9 *context9, T *params); + + unsigned int mGetDataAttemptCount; + GLuint64 mResult; + bool mQueryFinished; + + Renderer9 *mRenderer; + IDirect3DQuery9 *mQuery; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_QUERY9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp new file mode 100644 index 0000000000..9104bed617 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp @@ -0,0 +1,160 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderTarget9.cpp: Implements a D3D9-specific wrapper for IDirect3DSurface9 +// pointers retained by renderbuffers. + +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" + +namespace rx +{ + +// TODO: AddRef the incoming surface to take ownership instead of expecting that its ref is being +// given. +TextureRenderTarget9::TextureRenderTarget9(IDirect3DBaseTexture9 *texture, + size_t textureLevel, + IDirect3DSurface9 *surface, + GLenum internalFormat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLsizei samples) + : mWidth(width), + mHeight(height), + mDepth(depth), + mInternalFormat(internalFormat), + mD3DFormat(D3DFMT_UNKNOWN), + mSamples(samples), + mTexture(texture), + mTextureLevel(textureLevel), + mRenderTarget(surface) +{ + ASSERT(mDepth == 1); + + if (mRenderTarget) + { + D3DSURFACE_DESC description; + mRenderTarget->GetDesc(&description); + mD3DFormat = description.Format; + } +} + +TextureRenderTarget9::~TextureRenderTarget9() +{ + SafeRelease(mTexture); + SafeRelease(mRenderTarget); +} + +GLsizei TextureRenderTarget9::getWidth() const +{ + return mWidth; +} + +GLsizei TextureRenderTarget9::getHeight() const +{ + return mHeight; +} + +GLsizei TextureRenderTarget9::getDepth() const +{ + return mDepth; +} + +GLenum TextureRenderTarget9::getInternalFormat() const +{ + return mInternalFormat; +} + +GLsizei TextureRenderTarget9::getSamples() const +{ + return mSamples; +} + +IDirect3DBaseTexture9 *TextureRenderTarget9::getTexture() const +{ + return mTexture; +} + +size_t TextureRenderTarget9::getTextureLevel() const +{ + return mTextureLevel; +} + +IDirect3DSurface9 *TextureRenderTarget9::getSurface() const +{ + // Caller is responsible for releasing the returned surface reference. + // TODO: remove the AddRef to match RenderTarget11 + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + return mRenderTarget; +} + +D3DFORMAT TextureRenderTarget9::getD3DFormat() const +{ + return mD3DFormat; +} + +SurfaceRenderTarget9::SurfaceRenderTarget9(SwapChain9 *swapChain, bool depth) + : mSwapChain(swapChain), mDepth(depth) +{} + +SurfaceRenderTarget9::~SurfaceRenderTarget9() {} + +GLsizei SurfaceRenderTarget9::getWidth() const +{ + return mSwapChain->getWidth(); +} + +GLsizei SurfaceRenderTarget9::getHeight() const +{ + return mSwapChain->getHeight(); +} + +GLsizei SurfaceRenderTarget9::getDepth() const +{ + return 1; +} + +GLenum SurfaceRenderTarget9::getInternalFormat() const +{ + return (mDepth ? mSwapChain->getDepthBufferInternalFormat() + : mSwapChain->getRenderTargetInternalFormat()); +} + +GLsizei SurfaceRenderTarget9::getSamples() const +{ + // Our EGL surfaces do not support multisampling. + return 0; +} + +IDirect3DSurface9 *SurfaceRenderTarget9::getSurface() const +{ + return (mDepth ? mSwapChain->getDepthStencil() : mSwapChain->getRenderTarget()); +} + +IDirect3DBaseTexture9 *SurfaceRenderTarget9::getTexture() const +{ + return (mDepth ? nullptr : mSwapChain->getOffscreenTexture()); +} + +size_t SurfaceRenderTarget9::getTextureLevel() const +{ + return 0; +} + +D3DFORMAT SurfaceRenderTarget9::getD3DFormat() const +{ + return d3d9::GetTextureFormatInfo(getInternalFormat()).texFormat; +} + +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h new file mode 100644 index 0000000000..2b189479ab --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h @@ -0,0 +1,98 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderTarget9.h: Defines a D3D9-specific wrapper for IDirect3DSurface9 pointers +// retained by Renderbuffers. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_RENDERTARGET9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_RENDERTARGET9_H_ + +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" + +namespace rx +{ +class Renderer9; +class SwapChain9; + +class RenderTarget9 : public RenderTargetD3D +{ + public: + RenderTarget9() {} + ~RenderTarget9() override {} + // Retrieve the texture that backs this render target, may be null for swap chain render + // targets. + virtual IDirect3DBaseTexture9 *getTexture() const = 0; + virtual size_t getTextureLevel() const = 0; + + virtual IDirect3DSurface9 *getSurface() const = 0; + + virtual D3DFORMAT getD3DFormat() const = 0; +}; + +class TextureRenderTarget9 : public RenderTarget9 +{ + public: + TextureRenderTarget9(IDirect3DBaseTexture9 *texture, + size_t textureLevel, + IDirect3DSurface9 *surface, + GLenum internalFormat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLsizei samples); + ~TextureRenderTarget9() override; + + GLsizei getWidth() const override; + GLsizei getHeight() const override; + GLsizei getDepth() const override; + GLenum getInternalFormat() const override; + GLsizei getSamples() const override; + + IDirect3DBaseTexture9 *getTexture() const override; + size_t getTextureLevel() const override; + IDirect3DSurface9 *getSurface() const override; + + D3DFORMAT getD3DFormat() const override; + + private: + GLsizei mWidth; + GLsizei mHeight; + GLsizei mDepth; + GLenum mInternalFormat; + D3DFORMAT mD3DFormat; + GLsizei mSamples; + + IDirect3DBaseTexture9 *mTexture; + size_t mTextureLevel; + IDirect3DSurface9 *mRenderTarget; +}; + +class SurfaceRenderTarget9 : public RenderTarget9 +{ + public: + SurfaceRenderTarget9(SwapChain9 *swapChain, bool depth); + ~SurfaceRenderTarget9() override; + + GLsizei getWidth() const override; + GLsizei getHeight() const override; + GLsizei getDepth() const override; + GLenum getInternalFormat() const override; + GLsizei getSamples() const override; + + IDirect3DBaseTexture9 *getTexture() const override; + size_t getTextureLevel() const override; + IDirect3DSurface9 *getSurface() const override; + + D3DFORMAT getD3DFormat() const override; + + private: + SwapChain9 *mSwapChain; + bool mDepth; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_RENDERTARGET9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp new file mode 100644 index 0000000000..558023658d --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp @@ -0,0 +1,3239 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Renderer9.cpp: Implements a back-end specific class for the D3D9 renderer. + +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" + +#include <EGL/eglext.h> +#include <sstream> + +#include "common/utilities.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/Context.h" +#include "libANGLE/Display.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Program.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/State.h" +#include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/features.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/CompilerD3D.h" +#include "libANGLE/renderer/d3d/DeviceD3D.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/d3d/IndexDataManager.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" +#include "libANGLE/renderer/d3d/RenderbufferD3D.h" +#include "libANGLE/renderer/d3d/ShaderD3D.h" +#include "libANGLE/renderer/d3d/SurfaceD3D.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/d3d9/Blit9.h" +#include "libANGLE/renderer/d3d/d3d9/Buffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Context9.h" +#include "libANGLE/renderer/d3d/d3d9/Fence9.h" +#include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Image9.h" +#include "libANGLE/renderer/d3d/d3d9/IndexBuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/NativeWindow9.h" +#include "libANGLE/renderer/d3d/d3d9/Query9.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h" +#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h" +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" +#include "libANGLE/renderer/d3d/d3d9/VertexArray9.h" +#include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/trace.h" + +#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL) +# define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3 +#endif + +// Enable ANGLE_SUPPORT_SHADER_MODEL_2 if you wish devices with only shader model 2. +// Such a device would not be conformant. +#ifndef ANGLE_SUPPORT_SHADER_MODEL_2 +# define ANGLE_SUPPORT_SHADER_MODEL_2 0 +#endif + +namespace rx +{ + +namespace +{ +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 +}; + +template <typename T> +static void DrawPoints(IDirect3DDevice9 *device, GLsizei count, const void *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); + } +} + +// A hard limit on buffer size. This works around a problem in the NVIDIA drivers where buffer sizes +// close to MAX_UINT would give undefined results. The limit of MAX_UINT/2 should be generous enough +// for almost any demanding application. +constexpr UINT kMaximumBufferSizeHardLimit = std::numeric_limits<UINT>::max() >> 1; +} // anonymous namespace + +Renderer9::Renderer9(egl::Display *display) : RendererD3D(display), mStateManager(this) +{ + mD3d9Module = nullptr; + + mD3d9 = nullptr; + mD3d9Ex = nullptr; + mDevice = nullptr; + mDeviceEx = nullptr; + mDeviceWindow = nullptr; + mBlit = nullptr; + + mAdapter = D3DADAPTER_DEFAULT; + + const egl::AttributeMap &attributes = display->getAttributeMap(); + EGLint requestedDeviceType = static_cast<EGLint>(attributes.get( + EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE)); + switch (requestedDeviceType) + { + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE: + mDeviceType = D3DDEVTYPE_HAL; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_REFERENCE_ANGLE: + mDeviceType = D3DDEVTYPE_REF; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE: + mDeviceType = D3DDEVTYPE_NULLREF; + break; + + default: + UNREACHABLE(); + } + + mMaskedClearSavedState = nullptr; + + mVertexDataManager = nullptr; + mIndexDataManager = nullptr; + mLineLoopIB = nullptr; + mCountingIB = nullptr; + + mMaxNullColorbufferLRU = 0; + for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) + { + mNullRenderTargetCache[i].lruCount = 0; + mNullRenderTargetCache[i].width = 0; + mNullRenderTargetCache[i].height = 0; + mNullRenderTargetCache[i].renderTarget = nullptr; + } + + mAppliedVertexShader = nullptr; + mAppliedPixelShader = nullptr; + mAppliedProgramSerial = 0; + + gl::InitializeDebugAnnotations(&mAnnotator); +} + +Renderer9::~Renderer9() +{ + if (mDevice) + { + // If the device is lost, reset it first to prevent leaving the driver in an unstable state + if (testDeviceLost()) + { + resetDevice(); + } + } + + release(); +} + +void Renderer9::release() +{ + gl::UninitializeDebugAnnotations(); + + mTranslatedAttribCache.clear(); + + releaseDeviceResources(); + + SafeRelease(mDevice); + SafeRelease(mDeviceEx); + SafeRelease(mD3d9); + SafeRelease(mD3d9Ex); + + mCompiler.release(); + + if (mDeviceWindow) + { + DestroyWindow(mDeviceWindow); + mDeviceWindow = nullptr; + } + + mD3d9Module = nullptr; +} + +egl::Error Renderer9::initialize() +{ + ANGLE_TRACE_EVENT0("gpu.angle", "GetModuleHandle_d3d9"); + mD3d9Module = ::LoadLibrary(TEXT("d3d9.dll")); + + if (mD3d9Module == nullptr) + { + return egl::EglNotInitialized(D3D9_INIT_MISSING_DEP) << "No D3D9 module found."; + } + + typedef HRESULT(WINAPI * Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex **); + Direct3DCreate9ExFunc Direct3DCreate9ExPtr = + reinterpret_cast<Direct3DCreate9ExFunc>(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex")); + + // Use Direct3D9Ex if available. Among other things, this version is less + // inclined to report a lost context, for example when the user switches + // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are + // available. + if (ANGLE_D3D9EX == ANGLE_ENABLED && Direct3DCreate9ExPtr && + SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex))) + { + ANGLE_TRACE_EVENT0("gpu.angle", "D3d9Ex_QueryInterface"); + ASSERT(mD3d9Ex); + mD3d9Ex->QueryInterface(__uuidof(IDirect3D9), reinterpret_cast<void **>(&mD3d9)); + ASSERT(mD3d9); + } + else + { + ANGLE_TRACE_EVENT0("gpu.angle", "Direct3DCreate9"); + mD3d9 = Direct3DCreate9(D3D_SDK_VERSION); + } + + if (!mD3d9) + { + return egl::EglNotInitialized(D3D9_INIT_MISSING_DEP) << "Could not create D3D9 device."; + } + + if (mDisplay->getNativeDisplayId() != nullptr) + { + // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context + // corresponds to + } + + HRESULT result; + + // Give up on getting device caps after about one second. + { + ANGLE_TRACE_EVENT0("gpu.angle", "GetDeviceCaps"); + for (int i = 0; i < 10; ++i) + { + result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps); + if (SUCCEEDED(result)) + { + break; + } + else if (result == D3DERR_NOTAVAILABLE) + { + Sleep(100); // Give the driver some time to initialize/recover + } + else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, + // D3DERR_INVALIDDEVICE, or another error we can't recover + // from + { + return egl::EglNotInitialized(D3D9_INIT_OTHER_ERROR) + << "Failed to get device caps, " << gl::FmtHR(result); + } + } + } + +#if ANGLE_SUPPORT_SHADER_MODEL_2 + size_t minShaderModel = 2; +#else + size_t minShaderModel = 3; +#endif + + if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(minShaderModel, 0)) + { + return egl::EglNotInitialized(D3D9_INIT_UNSUPPORTED_VERSION) + << "Renderer does not support PS " << minShaderModel << ".0, aborting!"; + } + + // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture + // to a render target texture is not supported. This is required by + // Texture2D::ensureRenderTarget. + if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0) + { + return egl::EglNotInitialized(D3D9_INIT_UNSUPPORTED_STRETCHRECT) + << "Renderer does not support StretctRect from textures."; + } + + { + ANGLE_TRACE_EVENT0("gpu.angle", "GetAdapterIdentifier"); + mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier); + } + + static const TCHAR windowName[] = TEXT("AngleHiddenWindow"); + static const TCHAR className[] = TEXT("STATIC"); + + { + ANGLE_TRACE_EVENT0("gpu.angle", "CreateWindowEx"); + mDeviceWindow = + CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, + 1, HWND_MESSAGE, nullptr, GetModuleHandle(nullptr), nullptr); + } + + D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); + DWORD behaviorFlags = + D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED; + + { + ANGLE_TRACE_EVENT0("gpu.angle", "D3d9_CreateDevice"); + result = mD3d9->CreateDevice( + mAdapter, mDeviceType, mDeviceWindow, + behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, + &presentParameters, &mDevice); + } + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST) + { + return egl::EglBadAlloc(D3D9_INIT_OUT_OF_MEMORY) + << "CreateDevice failed: device lost of out of memory"; + } + + if (FAILED(result)) + { + ANGLE_TRACE_EVENT0("gpu.angle", "D3d9_CreateDevice2"); + result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, + behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &presentParameters, &mDevice); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || + result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST); + return egl::EglBadAlloc(D3D9_INIT_OUT_OF_MEMORY) + << "CreateDevice2 failed: device lost, not available, or of out of memory"; + } + } + + if (mD3d9Ex) + { + ANGLE_TRACE_EVENT0("gpu.angle", "mDevice_QueryInterface"); + result = mDevice->QueryInterface(__uuidof(IDirect3DDevice9Ex), (void **)&mDeviceEx); + ASSERT(SUCCEEDED(result)); + } + + { + ANGLE_TRACE_EVENT0("gpu.angle", "ShaderCache initialize"); + mVertexShaderCache.initialize(mDevice); + mPixelShaderCache.initialize(mDevice); + } + + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + // Check vertex texture support + // Only Direct3D 10 ready devices support all the necessary vertex texture formats. + // We test this using D3D9 by checking support for the R16F format. + mVertexTextureSupport = mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0) && + SUCCEEDED(mD3d9->CheckDeviceFormat( + mAdapter, mDeviceType, currentDisplayMode.Format, + D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F)); + + ANGLE_TRY(initializeDevice()); + + return egl::NoError(); +} + +// 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. +egl::Error Renderer9::initializeDevice() +{ + // Permanent non-default states + mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE); + mDevice->SetRenderState(D3DRS_LASTPIXEL, FALSE); + + if (mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) + { + mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, (DWORD &)mDeviceCaps.MaxPointSize); + } + else + { + mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, 0x3F800000); // 1.0f + } + + const gl::Caps &rendererCaps = getNativeCaps(); + + mCurVertexSamplerStates.resize(rendererCaps.maxShaderTextureImageUnits[gl::ShaderType::Vertex]); + mCurPixelSamplerStates.resize( + rendererCaps.maxShaderTextureImageUnits[gl::ShaderType::Fragment]); + + mCurVertexTextures.resize(rendererCaps.maxShaderTextureImageUnits[gl::ShaderType::Vertex]); + mCurPixelTextures.resize(rendererCaps.maxShaderTextureImageUnits[gl::ShaderType::Fragment]); + + markAllStateDirty(); + + mSceneStarted = false; + + ASSERT(!mBlit); + mBlit = new Blit9(this); + + ASSERT(!mVertexDataManager && !mIndexDataManager); + mIndexDataManager = new IndexDataManager(this); + + mTranslatedAttribCache.resize(getNativeCaps().maxVertexAttributes); + + mStateManager.initialize(); + + return egl::NoError(); +} + +D3DPRESENT_PARAMETERS Renderer9::getDefaultPresentParameters() +{ + D3DPRESENT_PARAMETERS presentParameters = {0}; + + // The default swap chain is never actually used. Surface will create a new swap chain with the + // proper parameters. + presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + presentParameters.BackBufferCount = 1; + presentParameters.BackBufferFormat = D3DFMT_UNKNOWN; + presentParameters.BackBufferWidth = 1; + presentParameters.BackBufferHeight = 1; + presentParameters.EnableAutoDepthStencil = FALSE; + presentParameters.Flags = 0; + presentParameters.hDeviceWindow = mDeviceWindow; + presentParameters.MultiSampleQuality = 0; + presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; + presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; + presentParameters.Windowed = TRUE; + + return presentParameters; +} + +egl::ConfigSet Renderer9::generateConfigs() +{ + static const GLenum colorBufferFormats[] = { + GL_BGR5_A1_ANGLEX, + GL_BGRA8_EXT, + GL_RGB565, + + }; + + static const GLenum depthStencilBufferFormats[] = { + GL_NONE, + GL_DEPTH_COMPONENT32_OES, + GL_DEPTH24_STENCIL8_OES, + GL_DEPTH_COMPONENT24_OES, + GL_DEPTH_COMPONENT16, + }; + + const gl::Caps &rendererCaps = getNativeCaps(); + const gl::TextureCapsMap &rendererTextureCaps = getNativeTextureCaps(); + + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + // Determine the min and max swap intervals + int minSwapInterval = 4; + int maxSwapInterval = 0; + + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) + { + minSwapInterval = std::min(minSwapInterval, 0); + maxSwapInterval = std::max(maxSwapInterval, 0); + } + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE) + { + minSwapInterval = std::min(minSwapInterval, 1); + maxSwapInterval = std::max(maxSwapInterval, 1); + } + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO) + { + minSwapInterval = std::min(minSwapInterval, 2); + maxSwapInterval = std::max(maxSwapInterval, 2); + } + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE) + { + minSwapInterval = std::min(minSwapInterval, 3); + maxSwapInterval = std::max(maxSwapInterval, 3); + } + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR) + { + minSwapInterval = std::min(minSwapInterval, 4); + maxSwapInterval = std::max(maxSwapInterval, 4); + } + + egl::ConfigSet configs; + for (size_t formatIndex = 0; formatIndex < ArraySize(colorBufferFormats); formatIndex++) + { + GLenum colorBufferInternalFormat = colorBufferFormats[formatIndex]; + const gl::TextureCaps &colorBufferFormatCaps = + rendererTextureCaps.get(colorBufferInternalFormat); + if (colorBufferFormatCaps.renderbuffer) + { + ASSERT(colorBufferFormatCaps.textureAttachment); + for (size_t depthStencilIndex = 0; + depthStencilIndex < ArraySize(depthStencilBufferFormats); depthStencilIndex++) + { + GLenum depthStencilBufferInternalFormat = + depthStencilBufferFormats[depthStencilIndex]; + const gl::TextureCaps &depthStencilBufferFormatCaps = + rendererTextureCaps.get(depthStencilBufferInternalFormat); + if (depthStencilBufferFormatCaps.renderbuffer || + depthStencilBufferInternalFormat == GL_NONE) + { + ASSERT(depthStencilBufferFormatCaps.textureAttachment || + depthStencilBufferInternalFormat == GL_NONE); + const gl::InternalFormat &colorBufferFormatInfo = + gl::GetSizedInternalFormatInfo(colorBufferInternalFormat); + const gl::InternalFormat &depthStencilBufferFormatInfo = + gl::GetSizedInternalFormatInfo(depthStencilBufferInternalFormat); + const d3d9::TextureFormat &d3d9ColorBufferFormatInfo = + d3d9::GetTextureFormatInfo(colorBufferInternalFormat); + + egl::Config config; + config.renderTargetFormat = colorBufferInternalFormat; + config.depthStencilFormat = depthStencilBufferInternalFormat; + config.bufferSize = colorBufferFormatInfo.pixelBytes * 8; + config.redSize = colorBufferFormatInfo.redBits; + config.greenSize = colorBufferFormatInfo.greenBits; + config.blueSize = colorBufferFormatInfo.blueBits; + config.luminanceSize = colorBufferFormatInfo.luminanceBits; + config.alphaSize = colorBufferFormatInfo.alphaBits; + config.alphaMaskSize = 0; + config.bindToTextureRGB = (colorBufferFormatInfo.format == GL_RGB); + config.bindToTextureRGBA = (colorBufferFormatInfo.format == GL_RGBA || + colorBufferFormatInfo.format == GL_BGRA_EXT); + config.colorBufferType = EGL_RGB_BUFFER; + // Mark as slow if blits to the back-buffer won't be straight forward + config.configCaveat = + (currentDisplayMode.Format == d3d9ColorBufferFormatInfo.renderFormat) + ? EGL_NONE + : EGL_SLOW_CONFIG; + config.configID = static_cast<EGLint>(configs.size() + 1); + config.conformant = EGL_OPENGL_ES2_BIT; + config.depthSize = depthStencilBufferFormatInfo.depthBits; + config.level = 0; + config.matchNativePixmap = EGL_NONE; + config.maxPBufferWidth = rendererCaps.max2DTextureSize; + config.maxPBufferHeight = rendererCaps.max2DTextureSize; + config.maxPBufferPixels = + rendererCaps.max2DTextureSize * rendererCaps.max2DTextureSize; + config.maxSwapInterval = maxSwapInterval; + config.minSwapInterval = minSwapInterval; + config.nativeRenderable = EGL_FALSE; + config.nativeVisualID = 0; + config.nativeVisualType = EGL_NONE; + config.renderableType = EGL_OPENGL_ES2_BIT; + config.sampleBuffers = 0; // FIXME: enumerate multi-sampling + config.samples = 0; + config.stencilSize = depthStencilBufferFormatInfo.stencilBits; + config.surfaceType = + EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT; + config.transparentType = EGL_NONE; + config.transparentRedValue = 0; + config.transparentGreenValue = 0; + config.transparentBlueValue = 0; + config.colorComponentType = gl_egl::GLComponentTypeToEGLColorComponentType( + colorBufferFormatInfo.componentType); + + configs.add(config); + } + } + } + } + + ASSERT(configs.size() > 0); + return configs; +} + +void Renderer9::generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const +{ + outExtensions->createContextRobustness = true; + + if (getShareHandleSupport()) + { + outExtensions->d3dShareHandleClientBuffer = true; + outExtensions->surfaceD3DTexture2DShareHandle = true; + } + outExtensions->d3dTextureClientBuffer = true; + + outExtensions->querySurfacePointer = true; + outExtensions->windowFixedSize = true; + outExtensions->postSubBuffer = true; + outExtensions->deviceQuery = true; + + outExtensions->image = true; + outExtensions->imageBase = true; + outExtensions->glTexture2DImage = true; + outExtensions->glRenderbufferImage = true; + + outExtensions->flexibleSurfaceCompatibility = true; + + // Contexts are virtualized so textures can be shared globally + outExtensions->displayTextureShareGroup = true; + + // D3D9 can be used without an output surface + outExtensions->surfacelessContext = true; + + outExtensions->robustResourceInitialization = true; +} + +void Renderer9::startScene() +{ + if (!mSceneStarted) + { + long result = mDevice->BeginScene(); + if (SUCCEEDED(result)) + { + // This is defensive checking against the device being + // lost at unexpected times. + mSceneStarted = true; + } + } +} + +void Renderer9::endScene() +{ + if (mSceneStarted) + { + // EndScene can fail if the device was lost, for example due + // to a TDR during a draw call. + mDevice->EndScene(); + mSceneStarted = false; + } +} + +angle::Result Renderer9::flush(const gl::Context *context) +{ + IDirect3DQuery9 *query = nullptr; + ANGLE_TRY(allocateEventQuery(context, &query)); + + Context9 *context9 = GetImplAs<Context9>(context); + + HRESULT result = query->Issue(D3DISSUE_END); + ANGLE_TRY_HR(context9, result, "Failed to issue event query"); + + // Grab the query data once + result = query->GetData(nullptr, 0, D3DGETDATA_FLUSH); + freeEventQuery(query); + ANGLE_TRY_HR(context9, result, "Failed to get event query data"); + + return angle::Result::Continue; +} + +angle::Result Renderer9::finish(const gl::Context *context) +{ + IDirect3DQuery9 *query = nullptr; + ANGLE_TRY(allocateEventQuery(context, &query)); + + Context9 *context9 = GetImplAs<Context9>(context); + + HRESULT result = query->Issue(D3DISSUE_END); + ANGLE_TRY_HR(context9, result, "Failed to issue event query"); + + // Grab the query data once + result = query->GetData(nullptr, 0, D3DGETDATA_FLUSH); + if (FAILED(result)) + { + freeEventQuery(query); + } + ANGLE_TRY_HR(context9, result, "Failed to get event query data"); + + // Loop until the query completes + unsigned int attempt = 0; + while (result == S_FALSE) + { + // Keep polling, but allow other threads to do something useful first + ScheduleYield(); + + result = query->GetData(nullptr, 0, D3DGETDATA_FLUSH); + attempt++; + + if (result == S_FALSE) + { + // 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 + bool checkDeviceLost = (attempt % kPollingD3DDeviceLostCheckFrequency) == 0; + if (checkDeviceLost && testDeviceLost()) + { + result = D3DERR_DEVICELOST; + } + } + + if (FAILED(result)) + { + freeEventQuery(query); + } + ANGLE_TRY_HR(context9, result, "Failed to get event query data"); + } + + freeEventQuery(query); + + return angle::Result::Continue; +} + +bool Renderer9::isValidNativeWindow(EGLNativeWindowType window) const +{ + return NativeWindow9::IsValidNativeWindow(window); +} + +NativeWindowD3D *Renderer9::createNativeWindow(EGLNativeWindowType window, + const egl::Config *, + const egl::AttributeMap &) const +{ + return new NativeWindow9(window); +} + +SwapChainD3D *Renderer9::createSwapChain(NativeWindowD3D *nativeWindow, + HANDLE shareHandle, + IUnknown *d3dTexture, + GLenum backBufferFormat, + GLenum depthBufferFormat, + EGLint orientation, + EGLint samples) +{ + return new SwapChain9(this, GetAs<NativeWindow9>(nativeWindow), shareHandle, d3dTexture, + backBufferFormat, depthBufferFormat, orientation); +} + +egl::Error Renderer9::getD3DTextureInfo(const egl::Config *configuration, + IUnknown *d3dTexture, + EGLint *width, + EGLint *height, + EGLint *samples, + const angle::Format **angleFormat) const +{ + IDirect3DTexture9 *texture = nullptr; + if (FAILED(d3dTexture->QueryInterface(&texture))) + { + return egl::EglBadParameter() << "Client buffer is not a IDirect3DTexture9"; + } + + IDirect3DDevice9 *textureDevice = nullptr; + texture->GetDevice(&textureDevice); + if (textureDevice != mDevice) + { + SafeRelease(texture); + return egl::EglBadParameter() << "Texture's device does not match."; + } + SafeRelease(textureDevice); + + D3DSURFACE_DESC desc; + texture->GetLevelDesc(0, &desc); + SafeRelease(texture); + + if (width) + { + *width = static_cast<EGLint>(desc.Width); + } + if (height) + { + *height = static_cast<EGLint>(desc.Height); + } + + // GetSamplesCount() returns 0 when multisampling isn't used. + GLsizei sampleCount = d3d9_gl::GetSamplesCount(desc.MultiSampleType); + if ((configuration && configuration->samples > 1) || sampleCount != 0) + { + return egl::EglBadParameter() << "Multisampling not supported for client buffer texture"; + } + if (samples) + { + *samples = static_cast<EGLint>(sampleCount); + } + + // From table egl.restrictions in EGL_ANGLE_d3d_texture_client_buffer. + switch (desc.Format) + { + case D3DFMT_R8G8B8: + case D3DFMT_A8R8G8B8: + case D3DFMT_A16B16G16R16F: + case D3DFMT_A32B32G32R32F: + break; + + default: + return egl::EglBadParameter() + << "Unknown client buffer texture format: " << desc.Format; + } + + if (angleFormat) + { + const auto &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); + ASSERT(d3dFormatInfo.info().id != angle::FormatID::NONE); + *angleFormat = &d3dFormatInfo.info(); + } + + return egl::NoError(); +} + +egl::Error Renderer9::validateShareHandle(const egl::Config *config, + HANDLE shareHandle, + const egl::AttributeMap &attribs) const +{ + if (shareHandle == nullptr) + { + return egl::EglBadParameter() << "NULL share handle."; + } + + EGLint width = attribs.getAsInt(EGL_WIDTH, 0); + EGLint height = attribs.getAsInt(EGL_HEIGHT, 0); + ASSERT(width != 0 && height != 0); + + const d3d9::TextureFormat &backBufferd3dFormatInfo = + d3d9::GetTextureFormatInfo(config->renderTargetFormat); + + IDirect3DTexture9 *texture = nullptr; + HRESULT result = mDevice->CreateTexture(width, height, 1, D3DUSAGE_RENDERTARGET, + backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT, + &texture, &shareHandle); + if (FAILED(result)) + { + return egl::EglBadParameter() << "Failed to open share handle, " << gl::FmtHR(result); + } + + DWORD levelCount = texture->GetLevelCount(); + + D3DSURFACE_DESC desc; + texture->GetLevelDesc(0, &desc); + SafeRelease(texture); + + if (levelCount != 1 || desc.Width != static_cast<UINT>(width) || + desc.Height != static_cast<UINT>(height) || + desc.Format != backBufferd3dFormatInfo.texFormat) + { + return egl::EglBadParameter() << "Invalid texture parameters in share handle texture."; + } + + return egl::NoError(); +} + +ContextImpl *Renderer9::createContext(const gl::State &state, gl::ErrorSet *errorSet) +{ + return new Context9(state, errorSet, this); +} + +void *Renderer9::getD3DDevice() +{ + return mDevice; +} + +angle::Result Renderer9::allocateEventQuery(const gl::Context *context, IDirect3DQuery9 **outQuery) +{ + if (mEventQueryPool.empty()) + { + HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, outQuery); + ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to allocate event query"); + } + else + { + *outQuery = mEventQueryPool.back(); + mEventQueryPool.pop_back(); + } + + return angle::Result::Continue; +} + +void Renderer9::freeEventQuery(IDirect3DQuery9 *query) +{ + if (mEventQueryPool.size() > 1000) + { + SafeRelease(query); + } + else + { + mEventQueryPool.push_back(query); + } +} + +angle::Result Renderer9::createVertexShader(d3d::Context *context, + const DWORD *function, + size_t length, + IDirect3DVertexShader9 **outShader) +{ + return mVertexShaderCache.create(context, function, length, outShader); +} + +angle::Result Renderer9::createPixelShader(d3d::Context *context, + const DWORD *function, + size_t length, + IDirect3DPixelShader9 **outShader) +{ + return mPixelShaderCache.create(context, function, length, outShader); +} + +HRESULT Renderer9::createVertexBuffer(UINT Length, + DWORD Usage, + IDirect3DVertexBuffer9 **ppVertexBuffer) +{ + // Force buffers to be limited to a fixed max size. + if (Length > kMaximumBufferSizeHardLimit) + { + return E_OUTOFMEMORY; + } + + D3DPOOL Pool = getBufferPool(Usage); + return mDevice->CreateVertexBuffer(Length, Usage, 0, Pool, ppVertexBuffer, nullptr); +} + +VertexBuffer *Renderer9::createVertexBuffer() +{ + return new VertexBuffer9(this); +} + +HRESULT Renderer9::createIndexBuffer(UINT Length, + DWORD Usage, + D3DFORMAT Format, + IDirect3DIndexBuffer9 **ppIndexBuffer) +{ + // Force buffers to be limited to a fixed max size. + if (Length > kMaximumBufferSizeHardLimit) + { + return E_OUTOFMEMORY; + } + + D3DPOOL Pool = getBufferPool(Usage); + return mDevice->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, nullptr); +} + +IndexBuffer *Renderer9::createIndexBuffer() +{ + return new IndexBuffer9(this); +} + +StreamProducerImpl *Renderer9::createStreamProducerD3DTexture( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) +{ + // Streams are not supported under D3D9 + UNREACHABLE(); + return nullptr; +} + +bool Renderer9::supportsFastCopyBufferToTexture(GLenum internalFormat) const +{ + // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3. + return false; +} + +angle::Result Renderer9::fastCopyBufferToTexture(const gl::Context *context, + const gl::PixelUnpackState &unpack, + unsigned int offset, + RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, + GLenum sourcePixelsType, + const gl::Box &destArea) +{ + // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3. + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); + return angle::Result::Stop; +} + +angle::Result Renderer9::setSamplerState(const gl::Context *context, + gl::ShaderType type, + int index, + gl::Texture *texture, + const gl::SamplerState &samplerState) +{ + CurSamplerState &appliedSampler = (type == gl::ShaderType::Fragment) + ? mCurPixelSamplerStates[index] + : mCurVertexSamplerStates[index]; + + // Make sure to add the level offset for our tiny compressed texture workaround + TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture); + + TextureStorage *storage = nullptr; + ANGLE_TRY(textureD3D->getNativeTexture(context, &storage)); + + // Storage should exist, texture should be complete + ASSERT(storage); + + DWORD baseLevel = texture->getBaseLevel() + storage->getTopLevel(); + + if (appliedSampler.forceSet || appliedSampler.baseLevel != baseLevel || + memcmp(&samplerState, &appliedSampler, sizeof(gl::SamplerState)) != 0) + { + int d3dSamplerOffset = (type == gl::ShaderType::Fragment) ? 0 : D3DVERTEXTEXTURESAMPLER0; + int d3dSampler = index + d3dSamplerOffset; + + mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, + gl_d3d9::ConvertTextureWrap(samplerState.getWrapS())); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, + gl_d3d9::ConvertTextureWrap(samplerState.getWrapT())); + + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, + gl_d3d9::ConvertMagFilter(samplerState.getMagFilter(), + samplerState.getMaxAnisotropy())); + + D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter; + float lodBias; + gl_d3d9::ConvertMinFilter(samplerState.getMinFilter(), &d3dMinFilter, &d3dMipFilter, + &lodBias, samplerState.getMaxAnisotropy(), baseLevel); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, baseLevel); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPMAPLODBIAS, static_cast<DWORD>(lodBias)); + if (getNativeExtensions().textureFilterAnisotropic) + { + DWORD maxAnisotropy = std::min(mDeviceCaps.MaxAnisotropy, + static_cast<DWORD>(samplerState.getMaxAnisotropy())); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, maxAnisotropy); + } + + ASSERT(texture->getBorderColor().type == angle::ColorGeneric::Type::Float); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_BORDERCOLOR, + gl_d3d9::ConvertColor(texture->getBorderColor().colorF)); + } + + appliedSampler.forceSet = false; + appliedSampler.samplerState = samplerState; + appliedSampler.baseLevel = baseLevel; + + return angle::Result::Continue; +} + +angle::Result Renderer9::setTexture(const gl::Context *context, + gl::ShaderType type, + int index, + gl::Texture *texture) +{ + int d3dSamplerOffset = (type == gl::ShaderType::Fragment) ? 0 : D3DVERTEXTEXTURESAMPLER0; + int d3dSampler = index + d3dSamplerOffset; + IDirect3DBaseTexture9 *d3dTexture = nullptr; + bool forceSetTexture = false; + + std::vector<uintptr_t> &appliedTextures = + (type == gl::ShaderType::Fragment) ? mCurPixelTextures : mCurVertexTextures; + + if (texture) + { + TextureD3D *textureImpl = GetImplAs<TextureD3D>(texture); + + TextureStorage *texStorage = nullptr; + ANGLE_TRY(textureImpl->getNativeTexture(context, &texStorage)); + + // Texture should be complete and have a storage + ASSERT(texStorage); + + TextureStorage9 *storage9 = GetAs<TextureStorage9>(texStorage); + ANGLE_TRY(storage9->getBaseTexture(context, &d3dTexture)); + + // 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 != nullptr); + + forceSetTexture = textureImpl->hasDirtyImages(); + textureImpl->resetDirty(); + } + + if (forceSetTexture || appliedTextures[index] != reinterpret_cast<uintptr_t>(d3dTexture)) + { + mDevice->SetTexture(d3dSampler, d3dTexture); + } + + appliedTextures[index] = reinterpret_cast<uintptr_t>(d3dTexture); + + return angle::Result::Continue; +} + +angle::Result Renderer9::updateState(const gl::Context *context, gl::PrimitiveMode drawMode) +{ + const auto &glState = context->getState(); + + // Applies the render target surface, depth stencil surface, viewport rectangle and + // scissor rectangle to the renderer + gl::Framebuffer *framebuffer = glState.getDrawFramebuffer(); + ASSERT(framebuffer && !framebuffer->hasAnyDirtyBit()); + + Framebuffer9 *framebuffer9 = GetImplAs<Framebuffer9>(framebuffer); + + ANGLE_TRY(applyRenderTarget(context, framebuffer9->getCachedColorRenderTargets()[0], + framebuffer9->getCachedDepthStencilRenderTarget())); + + // Setting viewport state + setViewport(glState.getViewport(), glState.getNearPlane(), glState.getFarPlane(), drawMode, + glState.getRasterizerState().frontFace, false); + + // Setting scissors state + setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled()); + + // Setting blend, depth stencil, and rasterizer states + // Since framebuffer->getSamples will return the original samples which may be different with + // the sample counts that we set in render target view, here we use renderTarget->getSamples to + // get the actual samples. + GLsizei samples = 0; + const gl::FramebufferAttachment *firstColorAttachment = framebuffer->getFirstColorAttachment(); + if (firstColorAttachment) + { + ASSERT(firstColorAttachment->isAttached()); + RenderTarget9 *renderTarget = nullptr; + ANGLE_TRY(firstColorAttachment->getRenderTarget(context, &renderTarget)); + samples = renderTarget->getSamples(); + } + gl::RasterizerState rasterizer = glState.getRasterizerState(); + rasterizer.pointDrawMode = (drawMode == gl::PrimitiveMode::Points); + rasterizer.multiSample = (samples != 0); + + ANGLE_TRY(setBlendDepthRasterStates(context, drawMode)); + + mStateManager.resetDirtyBits(); + + return angle::Result::Continue; +} + +void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) +{ + mStateManager.setScissorState(scissor, enabled); +} + +angle::Result Renderer9::setBlendDepthRasterStates(const gl::Context *context, + gl::PrimitiveMode drawMode) +{ + const auto &glState = context->getState(); + gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer(); + ASSERT(!drawFramebuffer->hasAnyDirtyBit()); + // Since framebuffer->getSamples will return the original samples which may be different with + // the sample counts that we set in render target view, here we use renderTarget->getSamples to + // get the actual samples. + GLsizei samples = 0; + const gl::FramebufferAttachment *firstColorAttachment = + drawFramebuffer->getFirstColorAttachment(); + if (firstColorAttachment) + { + ASSERT(firstColorAttachment->isAttached()); + RenderTarget9 *renderTarget = nullptr; + ANGLE_TRY(firstColorAttachment->getRenderTarget(context, &renderTarget)); + samples = renderTarget->getSamples(); + } + gl::RasterizerState rasterizer = glState.getRasterizerState(); + rasterizer.pointDrawMode = (drawMode == gl::PrimitiveMode::Points); + rasterizer.multiSample = (samples != 0); + + unsigned int mask = GetBlendSampleMask(glState, samples); + mStateManager.setBlendDepthRasterStates(glState, mask); + return angle::Result::Continue; +} + +void Renderer9::setViewport(const gl::Rectangle &viewport, + float zNear, + float zFar, + gl::PrimitiveMode drawMode, + GLenum frontFace, + bool ignoreViewport) +{ + mStateManager.setViewportState(viewport, zNear, zFar, drawMode, frontFace, ignoreViewport); +} + +bool Renderer9::applyPrimitiveType(gl::PrimitiveMode mode, GLsizei count, bool usesPointSize) +{ + switch (mode) + { + case gl::PrimitiveMode::Points: + mPrimitiveType = D3DPT_POINTLIST; + mPrimitiveCount = count; + break; + case gl::PrimitiveMode::Lines: + mPrimitiveType = D3DPT_LINELIST; + mPrimitiveCount = count / 2; + break; + case gl::PrimitiveMode::LineLoop: + mPrimitiveType = D3DPT_LINESTRIP; + mPrimitiveCount = + count - 1; // D3D doesn't support line loops, so we draw the last line separately + break; + case gl::PrimitiveMode::LineStrip: + mPrimitiveType = D3DPT_LINESTRIP; + mPrimitiveCount = count - 1; + break; + case gl::PrimitiveMode::Triangles: + mPrimitiveType = D3DPT_TRIANGLELIST; + mPrimitiveCount = count / 3; + break; + case gl::PrimitiveMode::TriangleStrip: + mPrimitiveType = D3DPT_TRIANGLESTRIP; + mPrimitiveCount = count - 2; + break; + case gl::PrimitiveMode::TriangleFan: + mPrimitiveType = D3DPT_TRIANGLEFAN; + mPrimitiveCount = count - 2; + break; + default: + UNREACHABLE(); + return false; + } + + return mPrimitiveCount > 0; +} + +angle::Result Renderer9::getNullColorRenderTarget(const gl::Context *context, + const RenderTarget9 *depthRenderTarget, + const RenderTarget9 **outColorRenderTarget) +{ + ASSERT(depthRenderTarget); + + const gl::Extents &size = depthRenderTarget->getExtents(); + + // search cached nullcolorbuffers + for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) + { + if (mNullRenderTargetCache[i].renderTarget != nullptr && + mNullRenderTargetCache[i].width == size.width && + mNullRenderTargetCache[i].height == size.height) + { + mNullRenderTargetCache[i].lruCount = ++mMaxNullColorbufferLRU; + *outColorRenderTarget = mNullRenderTargetCache[i].renderTarget; + return angle::Result::Continue; + } + } + + RenderTargetD3D *nullRenderTarget = nullptr; + ANGLE_TRY(createRenderTarget(context, size.width, size.height, GL_NONE, 0, &nullRenderTarget)); + + // add nullbuffer to the cache + NullRenderTargetCacheEntry *oldest = &mNullRenderTargetCache[0]; + for (int i = 1; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) + { + if (mNullRenderTargetCache[i].lruCount < oldest->lruCount) + { + oldest = &mNullRenderTargetCache[i]; + } + } + + SafeDelete(oldest->renderTarget); + oldest->renderTarget = GetAs<RenderTarget9>(nullRenderTarget); + oldest->lruCount = ++mMaxNullColorbufferLRU; + oldest->width = size.width; + oldest->height = size.height; + + *outColorRenderTarget = oldest->renderTarget; + return angle::Result::Continue; +} + +angle::Result Renderer9::applyRenderTarget(const gl::Context *context, + const RenderTarget9 *colorRenderTargetIn, + const RenderTarget9 *depthStencilRenderTarget) +{ + // 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. + const RenderTarget9 *colorRenderTarget = colorRenderTargetIn; + if (colorRenderTarget == nullptr) + { + ANGLE_TRY(getNullColorRenderTarget(context, depthStencilRenderTarget, &colorRenderTarget)); + } + ASSERT(colorRenderTarget != nullptr); + + size_t renderTargetWidth = 0; + size_t renderTargetHeight = 0; + D3DFORMAT renderTargetFormat = D3DFMT_UNKNOWN; + + bool renderTargetChanged = false; + unsigned int renderTargetSerial = colorRenderTarget->getSerial(); + if (renderTargetSerial != mAppliedRenderTargetSerial) + { + // Apply the render target on the device + IDirect3DSurface9 *renderTargetSurface = colorRenderTarget->getSurface(); + ASSERT(renderTargetSurface); + + mDevice->SetRenderTarget(0, renderTargetSurface); + SafeRelease(renderTargetSurface); + + renderTargetWidth = colorRenderTarget->getWidth(); + renderTargetHeight = colorRenderTarget->getHeight(); + renderTargetFormat = colorRenderTarget->getD3DFormat(); + + mAppliedRenderTargetSerial = renderTargetSerial; + renderTargetChanged = true; + } + + unsigned int depthStencilSerial = 0; + if (depthStencilRenderTarget != nullptr) + { + depthStencilSerial = depthStencilRenderTarget->getSerial(); + } + + if (depthStencilSerial != mAppliedDepthStencilSerial || !mDepthStencilInitialized) + { + unsigned int depthSize = 0; + unsigned int stencilSize = 0; + + // Apply the depth stencil on the device + if (depthStencilRenderTarget) + { + IDirect3DSurface9 *depthStencilSurface = depthStencilRenderTarget->getSurface(); + ASSERT(depthStencilSurface); + + mDevice->SetDepthStencilSurface(depthStencilSurface); + SafeRelease(depthStencilSurface); + + const gl::InternalFormat &format = + gl::GetSizedInternalFormatInfo(depthStencilRenderTarget->getInternalFormat()); + + depthSize = format.depthBits; + stencilSize = format.stencilBits; + } + else + { + mDevice->SetDepthStencilSurface(nullptr); + } + + mStateManager.updateDepthSizeIfChanged(mDepthStencilInitialized, depthSize); + mStateManager.updateStencilSizeIfChanged(mDepthStencilInitialized, stencilSize); + + mAppliedDepthStencilSerial = depthStencilSerial; + mDepthStencilInitialized = true; + } + + if (renderTargetChanged || !mRenderTargetDescInitialized) + { + mStateManager.forceSetBlendState(); + mStateManager.forceSetScissorState(); + mStateManager.setRenderTargetBounds(renderTargetWidth, renderTargetHeight); + mRenderTargetDescInitialized = true; + } + + return angle::Result::Continue; +} + +angle::Result Renderer9::applyVertexBuffer(const gl::Context *context, + gl::PrimitiveMode mode, + GLint first, + GLsizei count, + GLsizei instances, + TranslatedIndexData * /*indexInfo*/) +{ + const gl::State &state = context->getState(); + ANGLE_TRY(mVertexDataManager->prepareVertexData(context, first, count, &mTranslatedAttribCache, + instances)); + + return mVertexDeclarationCache.applyDeclaration(context, mDevice, mTranslatedAttribCache, + state.getProgram(), first, instances, + &mRepeatDraw); +} + +// Applies the indices and element array bindings to the Direct3D 9 device +angle::Result Renderer9::applyIndexBuffer(const gl::Context *context, + const void *indices, + GLsizei count, + gl::PrimitiveMode mode, + gl::DrawElementsType type, + TranslatedIndexData *indexInfo) +{ + gl::VertexArray *vao = context->getState().getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer(); + + gl::DrawElementsType dstType = gl::DrawElementsType::InvalidEnum; + ANGLE_TRY(GetIndexTranslationDestType(context, count, type, indices, false, &dstType)); + + ANGLE_TRY(mIndexDataManager->prepareIndexData(context, type, dstType, count, elementArrayBuffer, + indices, indexInfo)); + + // Directly binding the storage buffer is not supported for d3d9 + ASSERT(indexInfo->storage == nullptr); + + if (indexInfo->serial != mAppliedIBSerial) + { + IndexBuffer9 *indexBuffer = GetAs<IndexBuffer9>(indexInfo->indexBuffer); + + mDevice->SetIndices(indexBuffer->getBuffer()); + mAppliedIBSerial = indexInfo->serial; + } + + return angle::Result::Continue; +} + +angle::Result Renderer9::drawArraysImpl(const gl::Context *context, + gl::PrimitiveMode mode, + GLint startVertex, + GLsizei count, + GLsizei instances) +{ + ASSERT(!context->getState().isTransformFeedbackActiveUnpaused()); + + startScene(); + + if (mode == gl::PrimitiveMode::LineLoop) + { + return drawLineLoop(context, count, gl::DrawElementsType::InvalidEnum, nullptr, 0, nullptr); + } + + if (instances > 0) + { + StaticIndexBufferInterface *countingIB = nullptr; + ANGLE_TRY(getCountingIB(context, count, &countingIB)); + + if (mAppliedIBSerial != countingIB->getSerial()) + { + IndexBuffer9 *indexBuffer = GetAs<IndexBuffer9>(countingIB->getIndexBuffer()); + + mDevice->SetIndices(indexBuffer->getBuffer()); + mAppliedIBSerial = countingIB->getSerial(); + } + + for (int i = 0; i < mRepeatDraw; i++) + { + mDevice->DrawIndexedPrimitive(mPrimitiveType, 0, 0, count, 0, mPrimitiveCount); + } + + return angle::Result::Continue; + } + + // Regular case + mDevice->DrawPrimitive(mPrimitiveType, 0, mPrimitiveCount); + return angle::Result::Continue; +} + +angle::Result Renderer9::drawElementsImpl(const gl::Context *context, + gl::PrimitiveMode mode, + GLsizei count, + gl::DrawElementsType type, + const void *indices, + GLsizei instances) +{ + TranslatedIndexData indexInfo; + + ANGLE_TRY(applyIndexBuffer(context, indices, count, mode, type, &indexInfo)); + + gl::IndexRange indexRange; + ANGLE_TRY(context->getState().getVertexArray()->getIndexRange(context, type, count, indices, + &indexRange)); + + size_t vertexCount = indexRange.vertexCount(); + ANGLE_TRY(applyVertexBuffer(context, mode, static_cast<GLsizei>(indexRange.start), + static_cast<GLsizei>(vertexCount), instances, &indexInfo)); + + startScene(); + + int minIndex = static_cast<int>(indexRange.start); + + gl::VertexArray *vao = context->getState().getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer(); + + if (mode == gl::PrimitiveMode::Points) + { + return drawIndexedPoints(context, count, type, indices, minIndex, elementArrayBuffer); + } + + if (mode == gl::PrimitiveMode::LineLoop) + { + return drawLineLoop(context, count, type, indices, minIndex, elementArrayBuffer); + } + + for (int i = 0; i < mRepeatDraw; i++) + { + mDevice->DrawIndexedPrimitive(mPrimitiveType, -minIndex, minIndex, + static_cast<UINT>(vertexCount), indexInfo.startIndex, + mPrimitiveCount); + } + return angle::Result::Continue; +} + +angle::Result Renderer9::drawLineLoop(const gl::Context *context, + GLsizei count, + gl::DrawElementsType type, + const void *indices, + int minIndex, + gl::Buffer *elementArrayBuffer) +{ + // Get the raw indices for an indexed draw + if (type != gl::DrawElementsType::InvalidEnum && elementArrayBuffer) + { + BufferD3D *storage = GetImplAs<BufferD3D>(elementArrayBuffer); + intptr_t offset = reinterpret_cast<intptr_t>(indices); + const uint8_t *bufferData = nullptr; + ANGLE_TRY(storage->getData(context, &bufferData)); + indices = bufferData + offset; + } + + unsigned int startIndex = 0; + Context9 *context9 = GetImplAs<Context9>(context); + + if (getNativeExtensions().elementIndexUint) + { + if (!mLineLoopIB) + { + mLineLoopIB = new StreamingIndexBufferInterface(this); + ANGLE_TRY(mLineLoopIB->reserveBufferSpace(context, INITIAL_INDEX_BUFFER_SIZE, + gl::DrawElementsType::UnsignedInt)); + } + + // Checked by Renderer9::applyPrimitiveType + ASSERT(count >= 0); + + ANGLE_CHECK(context9, + static_cast<unsigned int>(count) + 1 <= + (std::numeric_limits<unsigned int>::max() / sizeof(unsigned int)), + "Failed to create a 32-bit looping index buffer for " + "GL_LINE_LOOP, too many indices required.", + GL_OUT_OF_MEMORY); + + const unsigned int spaceNeeded = + (static_cast<unsigned int>(count) + 1) * sizeof(unsigned int); + ANGLE_TRY(mLineLoopIB->reserveBufferSpace(context, spaceNeeded, + gl::DrawElementsType::UnsignedInt)); + + void *mappedMemory = nullptr; + unsigned int offset = 0; + ANGLE_TRY(mLineLoopIB->mapBuffer(context, spaceNeeded, &mappedMemory, &offset)); + + startIndex = static_cast<unsigned int>(offset) / 4; + unsigned int *data = static_cast<unsigned int *>(mappedMemory); + + switch (type) + { + case gl::DrawElementsType::InvalidEnum: // Non-indexed draw + for (int i = 0; i < count; i++) + { + data[i] = i; + } + data[count] = 0; + break; + case gl::DrawElementsType::UnsignedByte: + 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::DrawElementsType::UnsignedShort: + 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::DrawElementsType::UnsignedInt: + 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(); + } + + ANGLE_TRY(mLineLoopIB->unmapBuffer(context)); + } + else + { + if (!mLineLoopIB) + { + mLineLoopIB = new StreamingIndexBufferInterface(this); + ANGLE_TRY(mLineLoopIB->reserveBufferSpace(context, INITIAL_INDEX_BUFFER_SIZE, + gl::DrawElementsType::UnsignedShort)); + } + + // Checked by Renderer9::applyPrimitiveType + ASSERT(count >= 0); + + ANGLE_CHECK(context9, + static_cast<unsigned int>(count) + 1 <= + (std::numeric_limits<unsigned short>::max() / sizeof(unsigned short)), + "Failed to create a 16-bit looping index buffer for " + "GL_LINE_LOOP, too many indices required.", + GL_OUT_OF_MEMORY); + + const unsigned int spaceNeeded = + (static_cast<unsigned int>(count) + 1) * sizeof(unsigned short); + ANGLE_TRY(mLineLoopIB->reserveBufferSpace(context, spaceNeeded, + gl::DrawElementsType::UnsignedShort)); + + void *mappedMemory = nullptr; + unsigned int offset; + ANGLE_TRY(mLineLoopIB->mapBuffer(context, spaceNeeded, &mappedMemory, &offset)); + + startIndex = static_cast<unsigned int>(offset) / 2; + unsigned short *data = static_cast<unsigned short *>(mappedMemory); + + switch (type) + { + case gl::DrawElementsType::InvalidEnum: // Non-indexed draw + for (int i = 0; i < count; i++) + { + data[i] = static_cast<unsigned short>(i); + } + data[count] = 0; + break; + case gl::DrawElementsType::UnsignedByte: + 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::DrawElementsType::UnsignedShort: + 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::DrawElementsType::UnsignedInt: + for (int i = 0; i < count; i++) + { + data[i] = static_cast<unsigned short>(static_cast<const GLuint *>(indices)[i]); + } + data[count] = static_cast<unsigned short>(static_cast<const GLuint *>(indices)[0]); + break; + default: + UNREACHABLE(); + } + + ANGLE_TRY(mLineLoopIB->unmapBuffer(context)); + } + + if (mAppliedIBSerial != mLineLoopIB->getSerial()) + { + IndexBuffer9 *indexBuffer = GetAs<IndexBuffer9>(mLineLoopIB->getIndexBuffer()); + + mDevice->SetIndices(indexBuffer->getBuffer()); + mAppliedIBSerial = mLineLoopIB->getSerial(); + } + + mDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, -minIndex, minIndex, count, startIndex, count); + + return angle::Result::Continue; +} + +angle::Result Renderer9::drawIndexedPoints(const gl::Context *context, + GLsizei count, + gl::DrawElementsType type, + const void *indices, + int minIndex, + gl::Buffer *elementArrayBuffer) +{ + // Drawing index point lists is unsupported in d3d9, fall back to a regular DrawPrimitive call + // for each individual point. This call is not expected to happen often. + + if (elementArrayBuffer) + { + BufferD3D *storage = GetImplAs<BufferD3D>(elementArrayBuffer); + intptr_t offset = reinterpret_cast<intptr_t>(indices); + + const uint8_t *bufferData = nullptr; + ANGLE_TRY(storage->getData(context, &bufferData)); + indices = bufferData + offset; + } + + switch (type) + { + case gl::DrawElementsType::UnsignedByte: + DrawPoints<GLubyte>(mDevice, count, indices, minIndex); + return angle::Result::Continue; + case gl::DrawElementsType::UnsignedShort: + DrawPoints<GLushort>(mDevice, count, indices, minIndex); + return angle::Result::Continue; + case gl::DrawElementsType::UnsignedInt: + DrawPoints<GLuint>(mDevice, count, indices, minIndex); + return angle::Result::Continue; + default: + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); + } +} + +angle::Result Renderer9::getCountingIB(const gl::Context *context, + size_t count, + StaticIndexBufferInterface **outIB) +{ + // Update the counting index buffer if it is not large enough or has not been created yet. + if (count <= 65536) // 16-bit indices + { + const unsigned int spaceNeeded = static_cast<unsigned int>(count) * sizeof(unsigned short); + + if (!mCountingIB || mCountingIB->getBufferSize() < spaceNeeded) + { + SafeDelete(mCountingIB); + mCountingIB = new StaticIndexBufferInterface(this); + ANGLE_TRY(mCountingIB->reserveBufferSpace(context, spaceNeeded, + gl::DrawElementsType::UnsignedShort)); + + void *mappedMemory = nullptr; + ANGLE_TRY(mCountingIB->mapBuffer(context, spaceNeeded, &mappedMemory, nullptr)); + + unsigned short *data = static_cast<unsigned short *>(mappedMemory); + for (size_t i = 0; i < count; i++) + { + data[i] = static_cast<unsigned short>(i); + } + + ANGLE_TRY(mCountingIB->unmapBuffer(context)); + } + } + else if (getNativeExtensions().elementIndexUint) + { + const unsigned int spaceNeeded = static_cast<unsigned int>(count) * sizeof(unsigned int); + + if (!mCountingIB || mCountingIB->getBufferSize() < spaceNeeded) + { + SafeDelete(mCountingIB); + mCountingIB = new StaticIndexBufferInterface(this); + ANGLE_TRY(mCountingIB->reserveBufferSpace(context, spaceNeeded, + gl::DrawElementsType::UnsignedInt)); + + void *mappedMemory = nullptr; + ANGLE_TRY(mCountingIB->mapBuffer(context, spaceNeeded, &mappedMemory, nullptr)); + + unsigned int *data = static_cast<unsigned int *>(mappedMemory); + for (unsigned int i = 0; i < count; i++) + { + data[i] = i; + } + + ANGLE_TRY(mCountingIB->unmapBuffer(context)); + } + } + else + { + ANGLE_TRY_HR(GetImplAs<Context9>(context), E_OUTOFMEMORY, + "Could not create a counting index buffer for glDrawArraysInstanced."); + } + + *outIB = mCountingIB; + return angle::Result::Continue; +} + +angle::Result Renderer9::applyShaders(const gl::Context *context, gl::PrimitiveMode drawMode) +{ + const gl::State &state = context->getState(); + d3d::Context *contextD3D = GetImplAs<ContextD3D>(context); + + // This method is called single-threaded. + ANGLE_TRY(ensureHLSLCompilerInitialized(contextD3D)); + + ProgramD3D *programD3D = GetImplAs<ProgramD3D>(state.getProgram()); + VertexArray9 *vao = GetImplAs<VertexArray9>(state.getVertexArray()); + programD3D->updateCachedInputLayout(vao->getCurrentStateSerial(), state); + + ShaderExecutableD3D *vertexExe = nullptr; + ANGLE_TRY(programD3D->getVertexExecutableForCachedInputLayout(contextD3D, &vertexExe, nullptr)); + + const gl::Framebuffer *drawFramebuffer = state.getDrawFramebuffer(); + programD3D->updateCachedOutputLayout(context, drawFramebuffer); + + ShaderExecutableD3D *pixelExe = nullptr; + ANGLE_TRY(programD3D->getPixelExecutableForCachedOutputLayout(contextD3D, &pixelExe, nullptr)); + + IDirect3DVertexShader9 *vertexShader = + (vertexExe ? GetAs<ShaderExecutable9>(vertexExe)->getVertexShader() : nullptr); + IDirect3DPixelShader9 *pixelShader = + (pixelExe ? GetAs<ShaderExecutable9>(pixelExe)->getPixelShader() : nullptr); + + if (vertexShader != mAppliedVertexShader) + { + mDevice->SetVertexShader(vertexShader); + mAppliedVertexShader = vertexShader; + } + + if (pixelShader != mAppliedPixelShader) + { + mDevice->SetPixelShader(pixelShader); + mAppliedPixelShader = pixelShader; + } + + // D3D9 has a quirk where creating multiple shaders with the same content + // can return the same shader pointer. Because GL programs store different data + // per-program, checking the program serial guarantees we upload fresh + // uniform data even if our shader pointers are the same. + // https://code.google.com/p/angleproject/issues/detail?id=661 + unsigned int programSerial = programD3D->getSerial(); + if (programSerial != mAppliedProgramSerial) + { + programD3D->dirtyAllUniforms(); + mStateManager.forceSetDXUniformsState(); + mAppliedProgramSerial = programSerial; + } + + applyUniforms(programD3D); + + // Driver uniforms + mStateManager.setShaderConstants(); + + return angle::Result::Continue; +} + +void Renderer9::applyUniforms(ProgramD3D *programD3D) +{ + // Skip updates if we're not dirty. Note that D3D9 cannot have compute or geometry. + if (!programD3D->anyShaderUniformsDirty()) + { + return; + } + + const auto &uniformArray = programD3D->getD3DUniforms(); + + for (const D3DUniform *targetUniform : uniformArray) + { + // Built-in uniforms must be skipped. + if (!targetUniform->isReferencedByShader(gl::ShaderType::Vertex) && + !targetUniform->isReferencedByShader(gl::ShaderType::Fragment)) + continue; + + const GLfloat *f = reinterpret_cast<const GLfloat *>(targetUniform->firstNonNullData()); + const GLint *i = reinterpret_cast<const GLint *>(targetUniform->firstNonNullData()); + + switch (targetUniform->typeInfo.type) + { + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_EXTERNAL_OES: + break; + case GL_BOOL: + case GL_BOOL_VEC2: + case GL_BOOL_VEC3: + case GL_BOOL_VEC4: + applyUniformnbv(targetUniform, i); + break; + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT4: + applyUniformnfv(targetUniform, f); + break; + case GL_INT: + case GL_INT_VEC2: + case GL_INT_VEC3: + case GL_INT_VEC4: + applyUniformniv(targetUniform, i); + break; + default: + UNREACHABLE(); + } + } + + programD3D->markUniformsClean(); +} + +void Renderer9::applyUniformnfv(const D3DUniform *targetUniform, const GLfloat *v) +{ + if (targetUniform->isReferencedByShader(gl::ShaderType::Fragment)) + { + mDevice->SetPixelShaderConstantF( + targetUniform->mShaderRegisterIndexes[gl::ShaderType::Fragment], v, + targetUniform->registerCount); + } + + if (targetUniform->isReferencedByShader(gl::ShaderType::Vertex)) + { + mDevice->SetVertexShaderConstantF( + targetUniform->mShaderRegisterIndexes[gl::ShaderType::Vertex], v, + targetUniform->registerCount); + } +} + +void Renderer9::applyUniformniv(const D3DUniform *targetUniform, const GLint *v) +{ + ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9); + GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4]; + + for (unsigned int i = 0; i < targetUniform->registerCount; i++) + { + vector[i][0] = (GLfloat)v[4 * i + 0]; + vector[i][1] = (GLfloat)v[4 * i + 1]; + vector[i][2] = (GLfloat)v[4 * i + 2]; + vector[i][3] = (GLfloat)v[4 * i + 3]; + } + + applyUniformnfv(targetUniform, (GLfloat *)vector); +} + +void Renderer9::applyUniformnbv(const D3DUniform *targetUniform, const GLint *v) +{ + ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9); + GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4]; + + for (unsigned int i = 0; i < targetUniform->registerCount; i++) + { + vector[i][0] = (v[4 * i + 0] == GL_FALSE) ? 0.0f : 1.0f; + vector[i][1] = (v[4 * i + 1] == GL_FALSE) ? 0.0f : 1.0f; + vector[i][2] = (v[4 * i + 2] == GL_FALSE) ? 0.0f : 1.0f; + vector[i][3] = (v[4 * i + 3] == GL_FALSE) ? 0.0f : 1.0f; + } + + applyUniformnfv(targetUniform, (GLfloat *)vector); +} + +void Renderer9::clear(const ClearParameters &clearParams, + const RenderTarget9 *colorRenderTarget, + const RenderTarget9 *depthStencilRenderTarget) +{ + // Clearing buffers with non-float values is not supported by Renderer9 and ES 2.0 + ASSERT(clearParams.colorType == GL_FLOAT); + + // Clearing individual buffers other than buffer zero is not supported by Renderer9 and ES 2.0 + bool clearColor = clearParams.clearColor[0]; + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + ASSERT(clearParams.clearColor[i] == clearColor); + } + + float depth = gl::clamp01(clearParams.depthValue); + DWORD stencil = clearParams.stencilValue & 0x000000FF; + + unsigned int stencilUnmasked = 0x0; + if (clearParams.clearStencil && depthStencilRenderTarget) + { + const gl::InternalFormat &depthStencilFormat = + gl::GetSizedInternalFormatInfo(depthStencilRenderTarget->getInternalFormat()); + if (depthStencilFormat.stencilBits > 0) + { + const d3d9::D3DFormat &d3dFormatInfo = + d3d9::GetD3DFormatInfo(depthStencilRenderTarget->getD3DFormat()); + stencilUnmasked = (0x1 << d3dFormatInfo.stencilBits) - 1; + } + } + + const bool needMaskedStencilClear = + clearParams.clearStencil && + (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; + + bool needMaskedColorClear = false; + D3DCOLOR color = D3DCOLOR_ARGB(255, 0, 0, 0); + if (clearColor) + { + ASSERT(colorRenderTarget != nullptr); + + const gl::InternalFormat &formatInfo = + gl::GetSizedInternalFormatInfo(colorRenderTarget->getInternalFormat()); + const d3d9::D3DFormat &d3dFormatInfo = + d3d9::GetD3DFormatInfo(colorRenderTarget->getD3DFormat()); + + color = + D3DCOLOR_ARGB(gl::unorm<8>((formatInfo.alphaBits == 0 && d3dFormatInfo.alphaBits > 0) + ? 1.0f + : clearParams.colorF.alpha), + gl::unorm<8>((formatInfo.redBits == 0 && d3dFormatInfo.redBits > 0) + ? 0.0f + : clearParams.colorF.red), + gl::unorm<8>((formatInfo.greenBits == 0 && d3dFormatInfo.greenBits > 0) + ? 0.0f + : clearParams.colorF.green), + gl::unorm<8>((formatInfo.blueBits == 0 && d3dFormatInfo.blueBits > 0) + ? 0.0f + : clearParams.colorF.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 == nullptr) + { + 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(nullptr); + mDevice->SetVertexShader(nullptr); + mDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); + mDevice->SetStreamSource(0, nullptr, 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 != nullptr); + + if (mMaskedClearSavedState != nullptr) + { + 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(nullptr); + mDevice->SetVertexShader(nullptr); + mDevice->SetFVF(D3DFVF_XYZRHW); + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR); + mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color); + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mDevice->SetStreamSourceFreq(i, 1); + } + + int renderTargetWidth = mStateManager.getRenderTargetWidth(); + int renderTargetHeight = mStateManager.getRenderTargetHeight(); + + float quad[4][4]; // A quadrilateral covering the target, aligned to match the edges + quad[0][0] = -0.5f; + quad[0][1] = renderTargetHeight - 0.5f; + quad[0][2] = 0.0f; + quad[0][3] = 1.0f; + + quad[1][0] = renderTargetWidth - 0.5f; + quad[1][1] = renderTargetHeight - 0.5f; + quad[1][2] = 0.0f; + quad[1][3] = 1.0f; + + quad[2][0] = -0.5f; + quad[2][1] = -0.5f; + quad[2][2] = 0.0f; + quad[2][3] = 1.0f; + + quad[3][0] = renderTargetWidth - 0.5f; + quad[3][1] = -0.5f; + quad[3][2] = 0.0f; + quad[3][3] = 1.0f; + + startScene(); + mDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4])); + + if (clearParams.clearDepth) + { + mDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); + mDevice->Clear(0, nullptr, D3DCLEAR_ZBUFFER, color, depth, stencil); + } + + if (mMaskedClearSavedState != nullptr) + { + 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, nullptr, dxClearFlags, color, depth, stencil); + } +} + +void Renderer9::markAllStateDirty() +{ + mAppliedRenderTargetSerial = 0; + mAppliedDepthStencilSerial = 0; + mDepthStencilInitialized = false; + mRenderTargetDescInitialized = false; + + mStateManager.forceSetRasterState(); + mStateManager.forceSetDepthStencilState(); + mStateManager.forceSetBlendState(); + mStateManager.forceSetScissorState(); + mStateManager.forceSetViewportState(); + + ASSERT(mCurVertexSamplerStates.size() == mCurVertexTextures.size()); + for (unsigned int i = 0; i < mCurVertexTextures.size(); i++) + { + mCurVertexSamplerStates[i].forceSet = true; + mCurVertexTextures[i] = angle::DirtyPointer; + } + + ASSERT(mCurPixelSamplerStates.size() == mCurPixelTextures.size()); + for (unsigned int i = 0; i < mCurPixelSamplerStates.size(); i++) + { + mCurPixelSamplerStates[i].forceSet = true; + mCurPixelTextures[i] = angle::DirtyPointer; + } + + mAppliedIBSerial = 0; + mAppliedVertexShader = nullptr; + mAppliedPixelShader = nullptr; + mAppliedProgramSerial = 0; + mStateManager.forceSetDXUniformsState(); + + mVertexDeclarationCache.markStateDirty(); +} + +void Renderer9::releaseDeviceResources() +{ + for (size_t i = 0; i < mEventQueryPool.size(); i++) + { + SafeRelease(mEventQueryPool[i]); + } + mEventQueryPool.clear(); + + SafeRelease(mMaskedClearSavedState); + + mVertexShaderCache.clear(); + mPixelShaderCache.clear(); + + SafeDelete(mBlit); + SafeDelete(mVertexDataManager); + SafeDelete(mIndexDataManager); + SafeDelete(mLineLoopIB); + SafeDelete(mCountingIB); + + for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) + { + SafeDelete(mNullRenderTargetCache[i].renderTarget); + } +} + +// set notify to true to broadcast a message to all contexts of the device loss +bool Renderer9::testDeviceLost() +{ + HRESULT status = getDeviceStatusCode(); + return FAILED(status); +} + +HRESULT Renderer9::getDeviceStatusCode() +{ + HRESULT status = D3D_OK; + + if (mDeviceEx) + { + status = mDeviceEx->CheckDeviceState(nullptr); + } + 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 != nullptr); + case D3DERR_DEVICEREMOVED: + ASSERT(mDeviceEx != nullptr); + return isRemovedDeviceResettable(); + default: + return false; + } +} + +bool Renderer9::resetDevice() +{ + releaseDeviceResources(); + + D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); + + HRESULT result = D3D_OK; + bool lost = testDeviceLost(); + bool removedDevice = (getDeviceStatusCode() == D3DERR_DEVICEREMOVED); + + // Device Removed is a feature which is only present with D3D9Ex + ASSERT(mDeviceEx != nullptr || !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, nullptr); + lost = testDeviceLost(); + } + else + { + result = mDevice->TestCooperativeLevel(); + while (result == D3DERR_DEVICELOST) + { + Sleep(100); // Give the graphics driver some CPU time + result = mDevice->TestCooperativeLevel(); + } + + if (result == D3DERR_DEVICENOTRESET) + { + result = mDevice->Reset(&presentParameters); + } + lost = testDeviceLost(); + } + } + + if (FAILED(result)) + { + ERR() << "Reset/ResetEx failed multiple times, " << gl::FmtHR(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 + if (initializeDevice().isError()) + { + return false; + } + } + + return true; +} + +bool Renderer9::isRemovedDeviceResettable() const +{ + bool success = false; + +#if ANGLE_D3D9EX == ANGLE_ENABLED + IDirect3D9Ex *d3d9Ex = nullptr; + 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 + UNREACHABLE(); +#endif + + return success; +} + +bool Renderer9::resetRemovedDevice() +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/bb172554(v=vs.85).aspx: + // The hardware adapter has been removed. Application must destroy the device, do enumeration of + // adapters and create another Direct3D device. If application continues rendering without + // calling Reset, the rendering calls will succeed. Applies to Direct3D 9Ex only. + release(); + return !initialize().isError(); +} + +VendorID Renderer9::getVendorId() const +{ + return static_cast<VendorID>(mAdapterIdentifier.VendorId); +} + +std::string Renderer9::getRendererDescription() const +{ + std::ostringstream rendererString; + + rendererString << mAdapterIdentifier.Description; + if (getShareHandleSupport()) + { + rendererString << " Direct3D9Ex"; + } + else + { + rendererString << " Direct3D9"; + } + + rendererString << " vs_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.VertexShaderVersion) << "_" + << D3DSHADER_VERSION_MINOR(mDeviceCaps.VertexShaderVersion); + rendererString << " ps_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion) << "_" + << D3DSHADER_VERSION_MINOR(mDeviceCaps.PixelShaderVersion); + + return rendererString.str(); +} + +DeviceIdentifier Renderer9::getAdapterIdentifier() const +{ + DeviceIdentifier deviceIdentifier = {0}; + deviceIdentifier.VendorId = static_cast<UINT>(mAdapterIdentifier.VendorId); + deviceIdentifier.DeviceId = static_cast<UINT>(mAdapterIdentifier.DeviceId); + deviceIdentifier.SubSysId = static_cast<UINT>(mAdapterIdentifier.SubSysId); + deviceIdentifier.Revision = static_cast<UINT>(mAdapterIdentifier.Revision); + deviceIdentifier.FeatureLevel = 0; + + return deviceIdentifier; +} + +unsigned int Renderer9::getReservedVertexUniformVectors() const +{ + return d3d9_gl::GetReservedVertexUniformVectors(); +} + +unsigned int Renderer9::getReservedFragmentUniformVectors() const +{ + return d3d9_gl::GetReservedFragmentUniformVectors(); +} + +bool Renderer9::getShareHandleSupport() const +{ + // PIX doesn't seem to support using share handles, so disable them. + return (mD3d9Ex != nullptr) && !gl::DebugAnnotationsActive(); +} + +int Renderer9::getMajorShaderModel() const +{ + return D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion); +} + +int Renderer9::getMinorShaderModel() const +{ + return D3DSHADER_VERSION_MINOR(mDeviceCaps.PixelShaderVersion); +} + +std::string Renderer9::getShaderModelSuffix() const +{ + return ""; +} + +DWORD Renderer9::getCapsDeclTypes() const +{ + return mDeviceCaps.DeclTypes; +} + +D3DPOOL Renderer9::getBufferPool(DWORD usage) const +{ + if (mD3d9Ex != nullptr) + { + return D3DPOOL_DEFAULT; + } + else + { + if (!(usage & D3DUSAGE_DYNAMIC)) + { + return D3DPOOL_MANAGED; + } + } + + return D3DPOOL_DEFAULT; +} + +angle::Result Renderer9::copyImage2D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) +{ + RECT rect; + rect.left = sourceRect.x; + rect.top = sourceRect.y; + rect.right = sourceRect.x + sourceRect.width; + rect.bottom = sourceRect.y + sourceRect.height; + + return mBlit->copy2D(context, framebuffer, rect, destFormat, destOffset, storage, level); +} + +angle::Result Renderer9::copyImageCube(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + gl::TextureTarget 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(context, framebuffer, rect, destFormat, destOffset, storage, target, + level); +} + +angle::Result Renderer9::copyImage3D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) +{ + // 3D textures are not available in the D3D9 backend. + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); + return angle::Result::Stop; +} + +angle::Result Renderer9::copyImage2DArray(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) +{ + // 2D array textures are not available in the D3D9 backend. + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); + return angle::Result::Stop; +} + +angle::Result Renderer9::copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + gl::TextureTarget srcTarget, + const gl::Box &sourceBox, + GLenum destFormat, + GLenum destType, + const gl::Offset &destOffset, + TextureStorage *storage, + gl::TextureTarget destTarget, + GLint destLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) +{ + RECT rect; + rect.left = sourceBox.x; + rect.top = sourceBox.y; + rect.right = sourceBox.x + sourceBox.width; + rect.bottom = sourceBox.y + sourceBox.height; + + return mBlit->copyTexture(context, source, sourceLevel, rect, destFormat, destOffset, storage, + destTarget, destLevel, unpackFlipY, unpackPremultiplyAlpha, + unpackUnmultiplyAlpha); +} + +angle::Result Renderer9::copyCompressedTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + TextureStorage *storage, + GLint destLevel) +{ + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); + return angle::Result::Stop; +} + +angle::Result Renderer9::createRenderTarget(const gl::Context *context, + int width, + int height, + GLenum format, + GLsizei samples, + RenderTargetD3D **outRT) +{ + const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(format); + + const gl::TextureCaps &textureCaps = getNativeTextureCaps().get(format); + GLuint supportedSamples = textureCaps.getNearestSamples(samples); + + IDirect3DTexture9 *texture = nullptr; + IDirect3DSurface9 *renderTarget = nullptr; + if (width > 0 && height > 0) + { + bool requiresInitialization = false; + HRESULT result = D3DERR_INVALIDCALL; + + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(format); + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + result = mDevice->CreateDepthStencilSurface( + width, height, d3d9FormatInfo.renderFormat, + gl_d3d9::GetMultisampleType(supportedSamples), 0, FALSE, &renderTarget, nullptr); + } + else + { + requiresInitialization = (d3d9FormatInfo.dataInitializerFunction != nullptr); + if (supportedSamples > 0) + { + result = mDevice->CreateRenderTarget(width, height, d3d9FormatInfo.renderFormat, + gl_d3d9::GetMultisampleType(supportedSamples), + 0, FALSE, &renderTarget, nullptr); + } + else + { + result = mDevice->CreateTexture( + width, height, 1, D3DUSAGE_RENDERTARGET, d3d9FormatInfo.texFormat, + getTexturePool(D3DUSAGE_RENDERTARGET), &texture, nullptr); + if (!FAILED(result)) + { + result = texture->GetSurfaceLevel(0, &renderTarget); + } + } + } + + ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to create render target"); + + 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 = nullptr; + mDevice->GetRenderTarget(0, &prevRenderTarget); + mDevice->SetRenderTarget(0, renderTarget); + mDevice->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 0.0f, 0); + mDevice->SetRenderTarget(0, prevRenderTarget); + } + } + + *outRT = new TextureRenderTarget9(texture, 0, renderTarget, format, width, height, 1, + supportedSamples); + return angle::Result::Continue; +} + +angle::Result Renderer9::createRenderTargetCopy(const gl::Context *context, + RenderTargetD3D *source, + RenderTargetD3D **outRT) +{ + ASSERT(source != nullptr); + + RenderTargetD3D *newRT = nullptr; + ANGLE_TRY(createRenderTarget(context, source->getWidth(), source->getHeight(), + source->getInternalFormat(), source->getSamples(), &newRT)); + + RenderTarget9 *source9 = GetAs<RenderTarget9>(source); + RenderTarget9 *dest9 = GetAs<RenderTarget9>(newRT); + + HRESULT result = mDevice->StretchRect(source9->getSurface(), nullptr, dest9->getSurface(), + nullptr, D3DTEXF_NONE); + ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to copy render target"); + + *outRT = newRT; + return angle::Result::Continue; +} + +angle::Result Renderer9::loadExecutable(d3d::Context *context, + const uint8_t *function, + size_t length, + gl::ShaderType type, + const std::vector<D3DVarying> &streamOutVaryings, + bool separatedOutputBuffers, + ShaderExecutableD3D **outExecutable) +{ + // Transform feedback is not supported in ES2 or D3D9 + ASSERT(streamOutVaryings.empty()); + + switch (type) + { + case gl::ShaderType::Vertex: + { + IDirect3DVertexShader9 *vshader = nullptr; + ANGLE_TRY(createVertexShader(context, (DWORD *)function, length, &vshader)); + *outExecutable = new ShaderExecutable9(function, length, vshader); + } + break; + case gl::ShaderType::Fragment: + { + IDirect3DPixelShader9 *pshader = nullptr; + ANGLE_TRY(createPixelShader(context, (DWORD *)function, length, &pshader)); + *outExecutable = new ShaderExecutable9(function, length, pshader); + } + break; + default: + ANGLE_HR_UNREACHABLE(context); + } + + return angle::Result::Continue; +} + +angle::Result Renderer9::compileToExecutable(d3d::Context *context, + gl::InfoLog &infoLog, + const std::string &shaderHLSL, + gl::ShaderType type, + const std::vector<D3DVarying> &streamOutVaryings, + bool separatedOutputBuffers, + const angle::CompilerWorkaroundsD3D &workarounds, + ShaderExecutableD3D **outExectuable) +{ + // Transform feedback is not supported in ES2 or D3D9 + ASSERT(streamOutVaryings.empty()); + + std::stringstream profileStream; + + switch (type) + { + case gl::ShaderType::Vertex: + profileStream << "vs"; + break; + case gl::ShaderType::Fragment: + profileStream << "ps"; + break; + default: + ANGLE_HR_UNREACHABLE(context); + } + + profileStream << "_" << ((getMajorShaderModel() >= 3) ? 3 : 2); + profileStream << "_" + << "0"; + + std::string profile = profileStream.str(); + + UINT flags = ANGLE_COMPILE_OPTIMIZATION_LEVEL; + + if (workarounds.skipOptimization) + { + flags = D3DCOMPILE_SKIP_OPTIMIZATION; + } + else if (workarounds.useMaxOptimization) + { + flags = D3DCOMPILE_OPTIMIZATION_LEVEL3; + } + + if (gl::DebugAnnotationsActive()) + { +#ifndef NDEBUG + flags = D3DCOMPILE_SKIP_OPTIMIZATION; +#endif + + flags |= D3DCOMPILE_DEBUG; + } + + // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders + // when it would otherwise pass with alternative options. Try the default flags first and if + // compilation fails, try some alternatives. + std::vector<CompileConfig> configs; + configs.push_back(CompileConfig(flags, "default")); + configs.push_back(CompileConfig(flags | D3DCOMPILE_AVOID_FLOW_CONTROL, "avoid flow control")); + configs.push_back(CompileConfig(flags | D3DCOMPILE_PREFER_FLOW_CONTROL, "prefer flow control")); + + ID3DBlob *binary = nullptr; + std::string debugInfo; + angle::Result error = mCompiler.compileToBinary(context, infoLog, shaderHLSL, profile, configs, + nullptr, &binary, &debugInfo); + ANGLE_TRY(error); + + // It's possible that binary is NULL if the compiler failed in all configurations. Set the + // executable to NULL and return GL_NO_ERROR to signify that there was a link error but the + // internal state is still OK. + if (!binary) + { + *outExectuable = nullptr; + return angle::Result::Continue; + } + + error = loadExecutable(context, reinterpret_cast<const uint8_t *>(binary->GetBufferPointer()), + binary->GetBufferSize(), type, streamOutVaryings, separatedOutputBuffers, + outExectuable); + + SafeRelease(binary); + ANGLE_TRY(error); + + if (!debugInfo.empty()) + { + (*outExectuable)->appendDebugInfo(debugInfo); + } + + return angle::Result::Continue; +} + +angle::Result Renderer9::ensureHLSLCompilerInitialized(d3d::Context *context) +{ + return mCompiler.ensureInitialized(context); +} + +UniformStorageD3D *Renderer9::createUniformStorage(size_t storageSize) +{ + return new UniformStorageD3D(storageSize); +} + +angle::Result Renderer9::boxFilter(Context9 *context9, + IDirect3DSurface9 *source, + IDirect3DSurface9 *dest) +{ + return mBlit->boxFilter(context9, source, dest); +} + +D3DPOOL Renderer9::getTexturePool(DWORD usage) const +{ + if (mD3d9Ex != nullptr) + { + return D3DPOOL_DEFAULT; + } + else + { + if (!(usage & (D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET))) + { + return D3DPOOL_MANAGED; + } + } + + return D3DPOOL_DEFAULT; +} + +angle::Result Renderer9::copyToRenderTarget(const gl::Context *context, + IDirect3DSurface9 *dest, + IDirect3DSurface9 *source, + bool fromManaged) +{ + ASSERT(source && dest); + + Context9 *context9 = GetImplAs<Context9>(context); + + 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, nullptr); + + if (SUCCEEDED(result)) + { + ANGLE_TRY(Image9::CopyLockableSurfaces(context9, surf, source)); + result = mDevice->UpdateSurface(surf, nullptr, dest, nullptr); + SafeRelease(surf); + } + } + else + { + endScene(); + result = mDevice->StretchRect(source, nullptr, dest, nullptr, D3DTEXF_NONE); + } + + ANGLE_TRY_HR(context9, result, "Failed to blit internal texture"); + return angle::Result::Continue; +} + +RendererClass Renderer9::getRendererClass() const +{ + return RENDERER_D3D9; +} + +ImageD3D *Renderer9::createImage() +{ + return new Image9(this); +} + +ExternalImageSiblingImpl *Renderer9::createExternalImageSibling(const gl::Context *context, + EGLenum target, + EGLClientBuffer buffer, + const egl::AttributeMap &attribs) +{ + UNREACHABLE(); + return nullptr; +} + +angle::Result Renderer9::generateMipmap(const gl::Context *context, ImageD3D *dest, ImageD3D *src) +{ + Image9 *src9 = GetAs<Image9>(src); + Image9 *dst9 = GetAs<Image9>(dest); + return Image9::GenerateMipmap(GetImplAs<Context9>(context), dst9, src9); +} + +angle::Result Renderer9::generateMipmapUsingD3D(const gl::Context *context, + TextureStorage *storage, + const gl::TextureState &textureState) +{ + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); + return angle::Result::Stop; +} + +angle::Result Renderer9::copyImage(const gl::Context *context, + ImageD3D *dest, + ImageD3D *source, + const gl::Box &sourceBox, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) +{ + Image9 *dest9 = GetAs<Image9>(dest); + Image9 *src9 = GetAs<Image9>(source); + return Image9::CopyImage(context, dest9, src9, sourceBox.toRect(), destOffset, unpackFlipY, + unpackPremultiplyAlpha, unpackUnmultiplyAlpha); +} + +TextureStorage *Renderer9::createTextureStorage2D(SwapChainD3D *swapChain) +{ + SwapChain9 *swapChain9 = GetAs<SwapChain9>(swapChain); + return new TextureStorage9_2D(this, swapChain9); +} + +TextureStorage *Renderer9::createTextureStorageEGLImage(EGLImageD3D *eglImage, + RenderTargetD3D *renderTargetD3D) +{ + return new TextureStorage9_EGLImage(this, eglImage, GetAs<RenderTarget9>(renderTargetD3D)); +} + +TextureStorage *Renderer9::createTextureStorageExternal( + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) +{ + UNIMPLEMENTED(); + return nullptr; +} + +TextureStorage *Renderer9::createTextureStorage2D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + int levels, + bool hintLevelZeroOnly) +{ + return new TextureStorage9_2D(this, internalformat, renderTarget, width, height, levels); +} + +TextureStorage *Renderer9::createTextureStorageCube(GLenum internalformat, + bool renderTarget, + int size, + int levels, + bool hintLevelZeroOnly) +{ + return new TextureStorage9_Cube(this, internalformat, renderTarget, size, levels, + hintLevelZeroOnly); +} + +TextureStorage *Renderer9::createTextureStorage3D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) +{ + // 3D textures are not supported by the D3D9 backend. + UNREACHABLE(); + + return nullptr; +} + +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 nullptr; +} + +TextureStorage *Renderer9::createTextureStorage2DMultisample(GLenum internalformat, + GLsizei width, + GLsizei height, + int levels, + int samples, + bool fixedSampleLocations) +{ + // 2D multisampled textures are not supported by the D3D9 backend. + UNREACHABLE(); + + return nullptr; +} + +TextureStorage *Renderer9::createTextureStorage2DMultisampleArray(GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels, + int samples, + bool fixedSampleLocations) +{ + // 2D multisampled textures are not supported by the D3D9 backend. + UNREACHABLE(); + + return nullptr; +} + +bool Renderer9::getLUID(LUID *adapterLuid) const +{ + adapterLuid->HighPart = 0; + adapterLuid->LowPart = 0; + + if (mD3d9Ex) + { + mD3d9Ex->GetAdapterLUID(mAdapter, adapterLuid); + return true; + } + + return false; +} + +VertexConversionType Renderer9::getVertexConversionType(angle::FormatID vertexFormatID) const +{ + return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormatID).conversionType; +} + +GLenum Renderer9::getVertexComponentType(angle::FormatID vertexFormatID) const +{ + return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormatID).componentType; +} + +angle::Result Renderer9::getVertexSpaceRequired(const gl::Context *context, + const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + size_t count, + GLsizei instances, + unsigned int *bytesRequiredOut) const +{ + if (!attrib.enabled) + { + *bytesRequiredOut = 16u; + return angle::Result::Continue; + } + + angle::FormatID vertexFormatID = gl::GetVertexFormatID(attrib, gl::VertexAttribType::Float); + const d3d9::VertexFormat &d3d9VertexInfo = + d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormatID); + + unsigned int elementCount = 0; + const unsigned int divisor = binding.getDivisor(); + if (instances == 0 || divisor == 0) + { + elementCount = static_cast<unsigned int>(count); + } + else + { + // Round up to divisor, if possible + elementCount = UnsignedCeilDivide(static_cast<unsigned int>(instances), divisor); + } + + bool check = (d3d9VertexInfo.outputElementSize > + std::numeric_limits<unsigned int>::max() / elementCount); + ANGLE_CHECK(GetImplAs<Context9>(context), !check, + "New vertex buffer size would result in an overflow.", GL_OUT_OF_MEMORY); + + *bytesRequiredOut = static_cast<unsigned int>(d3d9VertexInfo.outputElementSize) * elementCount; + return angle::Result::Continue; +} + +void Renderer9::generateCaps(gl::Caps *outCaps, + gl::TextureCapsMap *outTextureCaps, + gl::Extensions *outExtensions, + gl::Limitations *outLimitations) const +{ + d3d9_gl::GenerateCaps(mD3d9, mDevice, mDeviceType, mAdapter, outCaps, outTextureCaps, + outExtensions, outLimitations); +} + +void Renderer9::initializeFeatures(angle::FeaturesD3D *features) const +{ + d3d9::InitializeFeatures(features); + OverrideFeaturesWithDisplayState(features, mDisplay->getState()); +} + +DeviceImpl *Renderer9::createEGLDevice() +{ + return new DeviceD3D(EGL_D3D9_DEVICE_ANGLE, mDevice); +} + +Renderer9::CurSamplerState::CurSamplerState() + : forceSet(true), baseLevel(std::numeric_limits<size_t>::max()), samplerState() +{} + +angle::Result Renderer9::genericDrawElements(const gl::Context *context, + gl::PrimitiveMode mode, + GLsizei count, + gl::DrawElementsType type, + const void *indices, + GLsizei instances) +{ + const gl::State &state = context->getState(); + gl::Program *program = context->getState().getProgram(); + ASSERT(program != nullptr); + ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program); + bool usesPointSize = programD3D->usesPointSize(); + + programD3D->updateSamplerMapping(); + + if (!applyPrimitiveType(mode, count, usesPointSize)) + { + return angle::Result::Continue; + } + + ANGLE_TRY(updateState(context, mode)); + ANGLE_TRY(applyTextures(context)); + ANGLE_TRY(applyShaders(context, mode)); + + if (!skipDraw(state, mode)) + { + ANGLE_TRY(drawElementsImpl(context, mode, count, type, indices, instances)); + } + + return angle::Result::Continue; +} + +angle::Result Renderer9::genericDrawArrays(const gl::Context *context, + gl::PrimitiveMode mode, + GLint first, + GLsizei count, + GLsizei instances) +{ + gl::Program *program = context->getState().getProgram(); + ASSERT(program != nullptr); + ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program); + bool usesPointSize = programD3D->usesPointSize(); + + programD3D->updateSamplerMapping(); + + if (!applyPrimitiveType(mode, count, usesPointSize)) + { + return angle::Result::Continue; + } + + ANGLE_TRY(updateState(context, mode)); + ANGLE_TRY(applyVertexBuffer(context, mode, first, count, instances, nullptr)); + ANGLE_TRY(applyTextures(context)); + ANGLE_TRY(applyShaders(context, mode)); + + if (!skipDraw(context->getState(), mode)) + { + ANGLE_TRY(drawArraysImpl(context, mode, first, count, instances)); + } + + return angle::Result::Continue; +} + +FramebufferImpl *Renderer9::createDefaultFramebuffer(const gl::FramebufferState &state) +{ + return new Framebuffer9(state, this); +} + +gl::Version Renderer9::getMaxSupportedESVersion() const +{ + return gl::Version(2, 0); +} + +gl::Version Renderer9::getMaxConformantESVersion() const +{ + return gl::Version(2, 0); +} + +angle::Result Renderer9::clearRenderTarget(const gl::Context *context, + RenderTargetD3D *renderTarget, + const gl::ColorF &clearColorValue, + const float clearDepthValue, + const unsigned int clearStencilValue) +{ + D3DCOLOR color = + D3DCOLOR_ARGB(gl::unorm<8>(clearColorValue.alpha), gl::unorm<8>(clearColorValue.red), + gl::unorm<8>(clearColorValue.green), gl::unorm<8>(clearColorValue.blue)); + float depth = clearDepthValue; + DWORD stencil = clearStencilValue & 0x000000FF; + + unsigned int renderTargetSerial = renderTarget->getSerial(); + RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTarget); + IDirect3DSurface9 *renderTargetSurface = renderTarget9->getSurface(); + ASSERT(renderTargetSurface); + + DWORD dxClearFlags = 0; + + const gl::InternalFormat &internalFormatInfo = + gl::GetSizedInternalFormatInfo(renderTarget->getInternalFormat()); + if (internalFormatInfo.depthBits > 0 || internalFormatInfo.stencilBits > 0) + { + dxClearFlags = D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL; + if (mAppliedDepthStencilSerial != renderTargetSerial) + { + mDevice->SetDepthStencilSurface(renderTargetSurface); + } + } + else + { + dxClearFlags = D3DCLEAR_TARGET; + if (mAppliedRenderTargetSerial != renderTargetSerial) + { + mDevice->SetRenderTarget(0, renderTargetSurface); + } + } + SafeRelease(renderTargetSurface); + + D3DVIEWPORT9 viewport; + viewport.X = 0; + viewport.Y = 0; + viewport.Width = renderTarget->getWidth(); + viewport.Height = renderTarget->getHeight(); + mDevice->SetViewport(&viewport); + + mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + + mDevice->Clear(0, nullptr, dxClearFlags, color, depth, stencil); + + markAllStateDirty(); + + return angle::Result::Continue; +} + +bool Renderer9::canSelectViewInVertexShader() const +{ + return false; +} + +// For each Direct3D sampler of either the pixel or vertex stage, +// looks up the corresponding OpenGL texture image unit and texture type, +// and sets the texture and its addressing/filtering state (or NULL when inactive). +// Sampler mapping needs to be up-to-date on the program object before this is called. +angle::Result Renderer9::applyTextures(const gl::Context *context, gl::ShaderType shaderType) +{ + const auto &glState = context->getState(); + const auto &caps = context->getCaps(); + ProgramD3D *programD3D = GetImplAs<ProgramD3D>(glState.getProgram()); + + ASSERT(!programD3D->isSamplerMappingDirty()); + + // TODO(jmadill): Use the Program's sampler bindings. + const gl::ActiveTexturePointerArray &activeTextures = glState.getActiveTexturesCache(); + + const gl::RangeUI samplerRange = programD3D->getUsedSamplerRange(shaderType); + for (unsigned int samplerIndex = samplerRange.low(); samplerIndex < samplerRange.high(); + samplerIndex++) + { + GLint textureUnit = programD3D->getSamplerMapping(shaderType, samplerIndex, caps); + ASSERT(textureUnit != -1); + gl::Texture *texture = activeTextures[textureUnit]; + + // A nullptr texture indicates incomplete. + if (texture) + { + gl::Sampler *samplerObject = glState.getSampler(textureUnit); + + const gl::SamplerState &samplerState = + samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState(); + + ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, texture, samplerState)); + ANGLE_TRY(setTexture(context, shaderType, samplerIndex, texture)); + } + else + { + gl::TextureType textureType = + programD3D->getSamplerTextureType(shaderType, samplerIndex); + + // Texture is not sampler complete or it is in use by the framebuffer. Bind the + // incomplete texture. + gl::Texture *incompleteTexture = nullptr; + ANGLE_TRY(getIncompleteTexture(context, textureType, &incompleteTexture)); + ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, incompleteTexture, + incompleteTexture->getSamplerState())); + ANGLE_TRY(setTexture(context, shaderType, samplerIndex, incompleteTexture)); + } + } + + // Set all the remaining textures to NULL + size_t samplerCount = (shaderType == gl::ShaderType::Fragment) + ? caps.maxShaderTextureImageUnits[gl::ShaderType::Fragment] + : caps.maxShaderTextureImageUnits[gl::ShaderType::Vertex]; + + // TODO(jmadill): faster way? + for (size_t samplerIndex = samplerRange.high(); samplerIndex < samplerCount; samplerIndex++) + { + ANGLE_TRY(setTexture(context, shaderType, static_cast<int>(samplerIndex), nullptr)); + } + + return angle::Result::Continue; +} + +angle::Result Renderer9::applyTextures(const gl::Context *context) +{ + ANGLE_TRY(applyTextures(context, gl::ShaderType::Vertex)); + ANGLE_TRY(applyTextures(context, gl::ShaderType::Fragment)); + return angle::Result::Continue; +} + +angle::Result Renderer9::getIncompleteTexture(const gl::Context *context, + gl::TextureType type, + gl::Texture **textureOut) +{ + return GetImplAs<Context9>(context)->getIncompleteTexture(context, type, textureOut); +} + +angle::Result Renderer9::ensureVertexDataManagerInitialized(const gl::Context *context) +{ + if (!mVertexDataManager) + { + mVertexDataManager = new VertexDataManager(this); + ANGLE_TRY(mVertexDataManager->initialize(context)); + } + + return angle::Result::Continue; +} +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Renderer9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Renderer9.h new file mode 100644 index 0000000000..9fa5fbfec4 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/Renderer9.h @@ -0,0 +1,580 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Renderer9.h: Defines a back-end specific class for the D3D9 renderer. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_RENDERER9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_RENDERER9_H_ + +#include "common/angleutils.h" +#include "common/mathutil.h" +#include "libANGLE/renderer/d3d/HLSLCompiler.h" +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h" +#include "libANGLE/renderer/d3d/d3d9/ShaderCache.h" +#include "libANGLE/renderer/d3d/d3d9/StateManager9.h" +#include "libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h" +#include "libANGLE/renderer/driver_utils.h" + +namespace gl +{ +class FramebufferAttachment; +} + +namespace egl +{ +class AttributeMap; +} + +namespace rx +{ +class Blit9; +class Context9; +class IndexDataManager; +class ProgramD3D; +class RenderTarget9; +class StreamingIndexBufferInterface; +class StaticIndexBufferInterface; +class VertexDataManager; +struct ClearParameters; +struct D3DUniform; +struct TranslatedAttribute; + +enum D3D9InitError +{ + D3D9_INIT_SUCCESS = 0, + // Failed to load the D3D or ANGLE compiler + D3D9_INIT_COMPILER_ERROR, + // Failed to load a necessary DLL + D3D9_INIT_MISSING_DEP, + // Device creation error + D3D9_INIT_CREATE_DEVICE_ERROR, + // System does not meet minimum shader spec + D3D9_INIT_UNSUPPORTED_VERSION, + // System does not support stretchrect from textures + D3D9_INIT_UNSUPPORTED_STRETCHRECT, + // A call returned out of memory or device lost + D3D9_INIT_OUT_OF_MEMORY, + // Other unspecified error + D3D9_INIT_OTHER_ERROR, + NUM_D3D9_INIT_ERRORS +}; + +class Renderer9 : public RendererD3D +{ + public: + explicit Renderer9(egl::Display *display); + ~Renderer9() override; + + egl::Error initialize() override; + bool resetDevice() override; + + egl::ConfigSet generateConfigs() override; + void generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const override; + + void startScene(); + void endScene(); + + angle::Result flush(const gl::Context *context); + angle::Result finish(const gl::Context *context); + + bool isValidNativeWindow(EGLNativeWindowType window) const override; + NativeWindowD3D *createNativeWindow(EGLNativeWindowType window, + const egl::Config *config, + const egl::AttributeMap &attribs) const override; + + SwapChainD3D *createSwapChain(NativeWindowD3D *nativeWindow, + HANDLE shareHandle, + IUnknown *d3dTexture, + GLenum backBufferFormat, + GLenum depthBufferFormat, + EGLint orientation, + EGLint samples) override; + egl::Error getD3DTextureInfo(const egl::Config *configuration, + IUnknown *d3dTexture, + EGLint *width, + EGLint *height, + EGLint *samples, + const angle::Format **angleFormat) const override; + egl::Error validateShareHandle(const egl::Config *config, + HANDLE shareHandle, + const egl::AttributeMap &attribs) const override; + + ContextImpl *createContext(const gl::State &state, gl::ErrorSet *errorSet) override; + + angle::Result allocateEventQuery(const gl::Context *context, IDirect3DQuery9 **outQuery); + void freeEventQuery(IDirect3DQuery9 *query); + + // resource creation + angle::Result createVertexShader(d3d::Context *context, + const DWORD *function, + size_t length, + IDirect3DVertexShader9 **outShader); + angle::Result createPixelShader(d3d::Context *context, + const DWORD *function, + size_t length, + IDirect3DPixelShader9 **outShader); + HRESULT createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer); + HRESULT createIndexBuffer(UINT Length, + DWORD Usage, + D3DFORMAT Format, + IDirect3DIndexBuffer9 **ppIndexBuffer); + angle::Result setSamplerState(const gl::Context *context, + gl::ShaderType type, + int index, + gl::Texture *texture, + const gl::SamplerState &sampler); + angle::Result setTexture(const gl::Context *context, + gl::ShaderType type, + int index, + gl::Texture *texture); + + angle::Result updateState(const gl::Context *context, gl::PrimitiveMode drawMode); + + void setScissorRectangle(const gl::Rectangle &scissor, bool enabled); + void setViewport(const gl::Rectangle &viewport, + float zNear, + float zFar, + gl::PrimitiveMode drawMode, + GLenum frontFace, + bool ignoreViewport); + + angle::Result applyRenderTarget(const gl::Context *context, + const RenderTarget9 *colorRenderTarget, + const RenderTarget9 *depthStencilRenderTarget); + void applyUniforms(ProgramD3D *programD3D); + bool applyPrimitiveType(gl::PrimitiveMode primitiveType, + GLsizei elementCount, + bool usesPointSize); + angle::Result applyVertexBuffer(const gl::Context *context, + gl::PrimitiveMode mode, + GLint first, + GLsizei count, + GLsizei instances, + TranslatedIndexData *indexInfo); + angle::Result applyIndexBuffer(const gl::Context *context, + const void *indices, + GLsizei count, + gl::PrimitiveMode mode, + gl::DrawElementsType type, + TranslatedIndexData *indexInfo); + + void clear(const ClearParameters &clearParams, + const RenderTarget9 *colorRenderTarget, + const RenderTarget9 *depthStencilRenderTarget); + + void markAllStateDirty(); + + // lost device + bool testDeviceLost() override; + bool testDeviceResettable() override; + + VendorID getVendorId() const; + std::string getRendererDescription() const; + DeviceIdentifier getAdapterIdentifier() const override; + + IDirect3DDevice9 *getDevice() { return mDevice; } + void *getD3DDevice() override; + + unsigned int getReservedVertexUniformVectors() const; + unsigned int getReservedFragmentUniformVectors() const; + + bool getShareHandleSupport() const; + + int getMajorShaderModel() const override; + int getMinorShaderModel() const override; + std::string getShaderModelSuffix() const override; + + DWORD getCapsDeclTypes() const; + + // Pixel operations + angle::Result copyImage2D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) override; + angle::Result copyImageCube(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + gl::TextureTarget target, + GLint level) override; + angle::Result copyImage3D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) override; + angle::Result copyImage2DArray(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) override; + + angle::Result copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + gl::TextureTarget srcTarget, + const gl::Box &sourceBox, + GLenum destFormat, + GLenum destType, + const gl::Offset &destOffset, + TextureStorage *storage, + gl::TextureTarget destTarget, + GLint destLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) override; + angle::Result copyCompressedTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + TextureStorage *storage, + GLint destLevel) override; + + // RenderTarget creation + angle::Result createRenderTarget(const gl::Context *context, + int width, + int height, + GLenum format, + GLsizei samples, + RenderTargetD3D **outRT) override; + angle::Result createRenderTargetCopy(const gl::Context *context, + RenderTargetD3D *source, + RenderTargetD3D **outRT) override; + + // Shader operations + angle::Result loadExecutable(d3d::Context *context, + const uint8_t *function, + size_t length, + gl::ShaderType type, + const std::vector<D3DVarying> &streamOutVaryings, + bool separatedOutputBuffers, + ShaderExecutableD3D **outExecutable) override; + angle::Result compileToExecutable(d3d::Context *context, + gl::InfoLog &infoLog, + const std::string &shaderHLSL, + gl::ShaderType type, + const std::vector<D3DVarying> &streamOutVaryings, + bool separatedOutputBuffers, + const angle::CompilerWorkaroundsD3D &workarounds, + ShaderExecutableD3D **outExectuable) override; + angle::Result ensureHLSLCompilerInitialized(d3d::Context *context) override; + + UniformStorageD3D *createUniformStorage(size_t storageSize) override; + + // Image operations + ImageD3D *createImage() override; + ExternalImageSiblingImpl *createExternalImageSibling(const gl::Context *context, + EGLenum target, + EGLClientBuffer buffer, + const egl::AttributeMap &attribs) override; + angle::Result generateMipmap(const gl::Context *context, + ImageD3D *dest, + ImageD3D *source) override; + angle::Result generateMipmapUsingD3D(const gl::Context *context, + TextureStorage *storage, + const gl::TextureState &textureState) override; + angle::Result copyImage(const gl::Context *context, + ImageD3D *dest, + ImageD3D *source, + const gl::Box &sourceBox, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) override; + TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) override; + TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage, + RenderTargetD3D *renderTargetD3D) override; + TextureStorage *createTextureStorageExternal( + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) override; + TextureStorage *createTextureStorage2D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + int levels, + bool hintLevelZeroOnly) override; + TextureStorage *createTextureStorageCube(GLenum internalformat, + bool renderTarget, + int size, + int levels, + bool hintLevelZeroOnly) override; + TextureStorage *createTextureStorage3D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) override; + TextureStorage *createTextureStorage2DArray(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) override; + + TextureStorage *createTextureStorage2DMultisample(GLenum internalformat, + GLsizei width, + GLsizei height, + int levels, + int samples, + bool fixedSampleLocations) override; + TextureStorage *createTextureStorage2DMultisampleArray(GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels, + int samples, + bool fixedSampleLocations) override; + + // Buffer creation + VertexBuffer *createVertexBuffer() override; + IndexBuffer *createIndexBuffer() override; + + // Stream Creation + StreamProducerImpl *createStreamProducerD3DTexture(egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) override; + + // Buffer-to-texture and Texture-to-buffer copies + bool supportsFastCopyBufferToTexture(GLenum internalFormat) const override; + angle::Result fastCopyBufferToTexture(const gl::Context *context, + const gl::PixelUnpackState &unpack, + unsigned int offset, + RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, + GLenum sourcePixelsType, + const gl::Box &destArea) override; + + // D3D9-renderer specific methods + angle::Result boxFilter(Context9 *context9, IDirect3DSurface9 *source, IDirect3DSurface9 *dest); + + D3DPOOL getTexturePool(DWORD usage) const; + + bool getLUID(LUID *adapterLuid) const override; + VertexConversionType getVertexConversionType(angle::FormatID vertexFormatID) const override; + GLenum getVertexComponentType(angle::FormatID vertexFormatID) const override; + + // Warning: you should ensure binding really matches attrib.bindingIndex before using this + // function. + angle::Result getVertexSpaceRequired(const gl::Context *context, + const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + size_t count, + GLsizei instances, + unsigned int *bytesRequiredOut) const override; + + angle::Result copyToRenderTarget(const gl::Context *context, + IDirect3DSurface9 *dest, + IDirect3DSurface9 *source, + bool fromManaged); + + RendererClass getRendererClass() const override; + + D3DDEVTYPE getD3D9DeviceType() const { return mDeviceType; } + + DeviceImpl *createEGLDevice() override; + + StateManager9 *getStateManager() { return &mStateManager; } + + angle::Result genericDrawArrays(const gl::Context *context, + gl::PrimitiveMode mode, + GLint first, + GLsizei count, + GLsizei instances); + + angle::Result genericDrawElements(const gl::Context *context, + gl::PrimitiveMode mode, + GLsizei count, + gl::DrawElementsType type, + const void *indices, + GLsizei instances); + + // Necessary hack for default framebuffers in D3D. + FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) override; + + DebugAnnotator9 *getAnnotator() { return &mAnnotator; } + + gl::Version getMaxSupportedESVersion() const override; + gl::Version getMaxConformantESVersion() const override; + + angle::Result clearRenderTarget(const gl::Context *context, + RenderTargetD3D *renderTarget, + const gl::ColorF &clearColorValue, + const float clearDepthValue, + const unsigned int clearStencilValue) override; + + bool canSelectViewInVertexShader() const override; + + angle::Result getIncompleteTexture(const gl::Context *context, + gl::TextureType type, + gl::Texture **textureOut) override; + + angle::Result ensureVertexDataManagerInitialized(const gl::Context *context); + + private: + angle::Result drawArraysImpl(const gl::Context *context, + gl::PrimitiveMode mode, + GLint startVertex, + GLsizei count, + GLsizei instances); + angle::Result drawElementsImpl(const gl::Context *context, + gl::PrimitiveMode mode, + GLsizei count, + gl::DrawElementsType type, + const void *indices, + GLsizei instances); + + angle::Result applyShaders(const gl::Context *context, gl::PrimitiveMode drawMode); + + angle::Result applyTextures(const gl::Context *context); + angle::Result applyTextures(const gl::Context *context, gl::ShaderType shaderType); + + void generateCaps(gl::Caps *outCaps, + gl::TextureCapsMap *outTextureCaps, + gl::Extensions *outExtensions, + gl::Limitations *outLimitations) const override; + + void initializeFeatures(angle::FeaturesD3D *features) const override; + + angle::Result setBlendDepthRasterStates(const gl::Context *context, gl::PrimitiveMode drawMode); + + void release(); + + void applyUniformnfv(const D3DUniform *targetUniform, const GLfloat *v); + void applyUniformniv(const D3DUniform *targetUniform, const GLint *v); + void applyUniformnbv(const D3DUniform *targetUniform, const GLint *v); + + angle::Result drawLineLoop(const gl::Context *context, + GLsizei count, + gl::DrawElementsType type, + const void *indices, + int minIndex, + gl::Buffer *elementArrayBuffer); + angle::Result drawIndexedPoints(const gl::Context *context, + GLsizei count, + gl::DrawElementsType type, + const void *indices, + int minIndex, + gl::Buffer *elementArrayBuffer); + + angle::Result getCountingIB(const gl::Context *context, + size_t count, + StaticIndexBufferInterface **outIB); + + angle::Result getNullColorRenderTarget(const gl::Context *context, + const RenderTarget9 *depthRenderTarget, + const RenderTarget9 **outColorRenderTarget); + + D3DPOOL getBufferPool(DWORD usage) const; + + HMODULE mD3d9Module; + + egl::Error initializeDevice(); + D3DPRESENT_PARAMETERS getDefaultPresentParameters(); + void releaseDeviceResources(); + + HRESULT getDeviceStatusCode(); + bool isRemovedDeviceResettable() const; + bool resetRemovedDevice(); + + UINT mAdapter; + D3DDEVTYPE mDeviceType; + IDirect3D9 *mD3d9; // Always valid after successful initialization. + IDirect3D9Ex *mD3d9Ex; // Might be null if D3D9Ex is not supported. + IDirect3DDevice9 *mDevice; + IDirect3DDevice9Ex *mDeviceEx; // Might be null if D3D9Ex is not supported. + + HLSLCompiler mCompiler; + + Blit9 *mBlit; + + HWND mDeviceWindow; + + D3DCAPS9 mDeviceCaps; + D3DADAPTER_IDENTIFIER9 mAdapterIdentifier; + + D3DPRIMITIVETYPE mPrimitiveType; + int mPrimitiveCount; + GLsizei mRepeatDraw; + + bool mSceneStarted; + + bool mVertexTextureSupport; + + // current render target states + unsigned int mAppliedRenderTargetSerial; + unsigned int mAppliedDepthStencilSerial; + bool mDepthStencilInitialized; + bool mRenderTargetDescInitialized; + + IDirect3DStateBlock9 *mMaskedClearSavedState; + + StateManager9 mStateManager; + + // Currently applied sampler states + struct CurSamplerState + { + CurSamplerState(); + + bool forceSet; + size_t baseLevel; + gl::SamplerState samplerState; + }; + std::vector<CurSamplerState> mCurVertexSamplerStates; + std::vector<CurSamplerState> mCurPixelSamplerStates; + + // Currently applied textures + std::vector<uintptr_t> mCurVertexTextures; + std::vector<uintptr_t> mCurPixelTextures; + + unsigned int mAppliedIBSerial; + IDirect3DVertexShader9 *mAppliedVertexShader; + IDirect3DPixelShader9 *mAppliedPixelShader; + unsigned int mAppliedProgramSerial; + + // A pool of event queries that are currently unused. + std::vector<IDirect3DQuery9 *> mEventQueryPool; + VertexShaderCache mVertexShaderCache; + PixelShaderCache mPixelShaderCache; + + VertexDataManager *mVertexDataManager; + VertexDeclarationCache mVertexDeclarationCache; + + IndexDataManager *mIndexDataManager; + StreamingIndexBufferInterface *mLineLoopIB; + StaticIndexBufferInterface *mCountingIB; + + enum + { + NUM_NULL_COLORBUFFER_CACHE_ENTRIES = 12 + }; + struct NullRenderTargetCacheEntry + { + UINT lruCount; + int width; + int height; + RenderTarget9 *renderTarget; + }; + + std::array<NullRenderTargetCacheEntry, NUM_NULL_COLORBUFFER_CACHE_ENTRIES> + mNullRenderTargetCache; + UINT mMaxNullColorbufferLRU; + + std::vector<TranslatedAttribute> mTranslatedAttribCache; + + DebugAnnotator9 mAnnotator; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_RENDERER9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h new file mode 100644 index 0000000000..1aef503ba5 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h @@ -0,0 +1,110 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ShaderCache: Defines rx::ShaderCache, a cache of Direct3D shader objects +// keyed by their byte code. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_SHADERCACHE_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_SHADERCACHE_H_ + +#include "libANGLE/Error.h" + +#include "common/debug.h" +#include "libANGLE/renderer/d3d/d3d9/Context9.h" + +#include <cstddef> +#include <mutex> +#include <string> +#include <unordered_map> + +namespace rx +{ +template <typename ShaderObject> +class ShaderCache : angle::NonCopyable +{ + public: + ShaderCache() : mDevice(nullptr) {} + + ~ShaderCache() + { + // Call clear while the device is still valid. + ASSERT(mMap.empty()); + } + + void initialize(IDirect3DDevice9 *device) { mDevice = device; } + + angle::Result create(d3d::Context *context, + const DWORD *function, + size_t length, + ShaderObject **outShaderObject) + { + std::lock_guard<std::mutex> lock(mMutex); + + std::string key(reinterpret_cast<const char *>(function), length); + typename Map::iterator it = mMap.find(key); + if (it != mMap.end()) + { + it->second->AddRef(); + *outShaderObject = it->second; + return angle::Result::Continue; + } + + ShaderObject *shader; + HRESULT result = createShader(function, &shader); + ANGLE_TRY_HR(context, result, "Failed to create shader"); + + // Random eviction policy. + if (mMap.size() >= kMaxMapSize) + { + SafeRelease(mMap.begin()->second); + mMap.erase(mMap.begin()); + } + + shader->AddRef(); + mMap[key] = shader; + + *outShaderObject = shader; + return angle::Result::Continue; + } + + void clear() + { + std::lock_guard<std::mutex> lock(mMutex); + + for (typename Map::iterator it = mMap.begin(); it != mMap.end(); ++it) + { + SafeRelease(it->second); + } + + mMap.clear(); + } + + private: + const static size_t kMaxMapSize = 100; + + HRESULT createShader(const DWORD *function, IDirect3DVertexShader9 **shader) + { + return mDevice->CreateVertexShader(function, shader); + } + + HRESULT createShader(const DWORD *function, IDirect3DPixelShader9 **shader) + { + return mDevice->CreatePixelShader(function, shader); + } + + typedef std::unordered_map<std::string, ShaderObject *> Map; + Map mMap; + std::mutex mMutex; + + IDirect3DDevice9 *mDevice; +}; + +typedef ShaderCache<IDirect3DVertexShader9> VertexShaderCache; +typedef ShaderCache<IDirect3DPixelShader9> PixelShaderCache; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_SHADERCACHE_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp new file mode 100644 index 0000000000..c9e8e73ed6 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp @@ -0,0 +1,51 @@ +// +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ShaderExecutable9.cpp: Implements a D3D9-specific class to contain shader +// executable implementation details. + +#include "libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h" + +#include "common/debug.h" + +namespace rx +{ + +ShaderExecutable9::ShaderExecutable9(const void *function, + size_t length, + IDirect3DPixelShader9 *executable) + : ShaderExecutableD3D(function, length) +{ + mPixelExecutable = executable; + mVertexExecutable = nullptr; +} + +ShaderExecutable9::ShaderExecutable9(const void *function, + size_t length, + IDirect3DVertexShader9 *executable) + : ShaderExecutableD3D(function, length) +{ + mVertexExecutable = executable; + mPixelExecutable = nullptr; +} + +ShaderExecutable9::~ShaderExecutable9() +{ + SafeRelease(mVertexExecutable); + SafeRelease(mPixelExecutable); +} + +IDirect3DVertexShader9 *ShaderExecutable9::getVertexShader() const +{ + return mVertexExecutable; +} + +IDirect3DPixelShader9 *ShaderExecutable9::getPixelShader() const +{ + return mPixelExecutable; +} + +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h new file mode 100644 index 0000000000..599a166870 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h @@ -0,0 +1,35 @@ +// +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ShaderExecutable9.h: Defines a D3D9-specific class to contain shader +// executable implementation details. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_SHADEREXECUTABLE9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_SHADEREXECUTABLE9_H_ + +#include "libANGLE/renderer/d3d/ShaderExecutableD3D.h" + +namespace rx +{ + +class ShaderExecutable9 : public ShaderExecutableD3D +{ + public: + ShaderExecutable9(const void *function, size_t length, IDirect3DPixelShader9 *executable); + ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable); + ~ShaderExecutable9() override; + + IDirect3DPixelShader9 *getPixelShader() const; + IDirect3DVertexShader9 *getVertexShader() const; + + private: + IDirect3DPixelShader9 *mPixelExecutable; + IDirect3DVertexShader9 *mVertexExecutable; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_SHADEREXECUTABLE9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp new file mode 100644 index 0000000000..74bbe53fd8 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp @@ -0,0 +1,938 @@ +// +// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// StateManager9.cpp: Defines a class for caching D3D9 state +#include "libANGLE/renderer/d3d/d3d9/StateManager9.h" + +#include "common/bitset_utils.h" +#include "common/utilities.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" + +namespace rx +{ + +StateManager9::StateManager9(Renderer9 *renderer9) + : mUsingZeroColorMaskWorkaround(false), + mCurBlendState(), + mCurBlendColor(0, 0, 0, 0), + mCurSampleMask(0), + mCurRasterState(), + mCurDepthSize(0), + mCurDepthStencilState(), + mCurStencilRef(0), + mCurStencilBackRef(0), + mCurFrontFaceCCW(0), + mCurStencilSize(0), + mCurScissorRect(), + mCurScissorEnabled(false), + mCurViewport(), + mCurNear(0.0f), + mCurFar(0.0f), + mCurDepthFront(0.0f), + mCurIgnoreViewport(false), + mRenderer9(renderer9), + mDirtyBits() +{ + mBlendStateDirtyBits.set(DIRTY_BIT_BLEND_ENABLED); + mBlendStateDirtyBits.set(DIRTY_BIT_BLEND_COLOR); + mBlendStateDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS); + mBlendStateDirtyBits.set(DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE); + mBlendStateDirtyBits.set(DIRTY_BIT_COLOR_MASK); + mBlendStateDirtyBits.set(DIRTY_BIT_DITHER); + mBlendStateDirtyBits.set(DIRTY_BIT_SAMPLE_MASK); + + mRasterizerStateDirtyBits.set(DIRTY_BIT_CULL_MODE); + mRasterizerStateDirtyBits.set(DIRTY_BIT_DEPTH_BIAS); + + mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_MASK); + mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_FUNC); + mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_TEST_ENABLED); + mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_FRONT); + mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_BACK); + mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT); + mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK); + mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_OPS_FRONT); + mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_OPS_BACK); + + mScissorStateDirtyBits.set(DIRTY_BIT_SCISSOR_ENABLED); + mScissorStateDirtyBits.set(DIRTY_BIT_SCISSOR_RECT); +} + +StateManager9::~StateManager9() {} + +void StateManager9::initialize() +{ + mUsingZeroColorMaskWorkaround = IsAMD(mRenderer9->getVendorId()); +} + +void StateManager9::forceSetBlendState() +{ + mDirtyBits |= mBlendStateDirtyBits; +} + +void StateManager9::forceSetRasterState() +{ + mDirtyBits |= mRasterizerStateDirtyBits; +} + +void StateManager9::forceSetDepthStencilState() +{ + mDirtyBits |= mDepthStencilStateDirtyBits; +} + +void StateManager9::forceSetScissorState() +{ + mDirtyBits |= mScissorStateDirtyBits; +} + +void StateManager9::forceSetViewportState() +{ + mForceSetViewport = true; +} + +void StateManager9::forceSetDXUniformsState() +{ + mDxUniformsDirty = true; +} + +void StateManager9::updateStencilSizeIfChanged(bool depthStencilInitialized, + unsigned int stencilSize) +{ + if (!depthStencilInitialized || stencilSize != mCurStencilSize) + { + mCurStencilSize = stencilSize; + forceSetDepthStencilState(); + } +} + +void StateManager9::syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits) +{ + if (!dirtyBits.any()) + { + return; + } + + for (auto dirtyBit : dirtyBits) + { + switch (dirtyBit) + { + case gl::State::DIRTY_BIT_BLEND_ENABLED: + if (state.getBlendState().blend != mCurBlendState.blend) + { + mDirtyBits.set(DIRTY_BIT_BLEND_ENABLED); + // BlendColor and funcs and equations has to be set if blend is enabled + mDirtyBits.set(DIRTY_BIT_BLEND_COLOR); + mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS); + + // The color mask may have to be updated if the blend state changes + if (mUsingZeroColorMaskWorkaround) + { + mDirtyBits.set(DIRTY_BIT_COLOR_MASK); + } + } + break; + case gl::State::DIRTY_BIT_BLEND_FUNCS: + { + const gl::BlendState &blendState = state.getBlendState(); + if (blendState.sourceBlendRGB != mCurBlendState.sourceBlendRGB || + blendState.destBlendRGB != mCurBlendState.destBlendRGB || + blendState.sourceBlendAlpha != mCurBlendState.sourceBlendAlpha || + blendState.destBlendAlpha != mCurBlendState.destBlendAlpha) + { + mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS); + // BlendColor depends on the values of blend funcs + mDirtyBits.set(DIRTY_BIT_BLEND_COLOR); + + // The color mask may have to be updated if the blend funcs change + if (mUsingZeroColorMaskWorkaround) + { + mDirtyBits.set(DIRTY_BIT_COLOR_MASK); + } + } + break; + } + case gl::State::DIRTY_BIT_BLEND_EQUATIONS: + { + const gl::BlendState &blendState = state.getBlendState(); + if (blendState.blendEquationRGB != mCurBlendState.blendEquationRGB || + blendState.blendEquationAlpha != mCurBlendState.blendEquationAlpha) + { + mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS); + + // The color mask may have to be updated if the blend funcs change + if (mUsingZeroColorMaskWorkaround) + { + mDirtyBits.set(DIRTY_BIT_COLOR_MASK); + } + } + break; + } + case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED: + if (state.getBlendState().sampleAlphaToCoverage != + mCurBlendState.sampleAlphaToCoverage) + { + mDirtyBits.set(DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE); + } + break; + case gl::State::DIRTY_BIT_COLOR_MASK: + { + const gl::BlendState &blendState = state.getBlendState(); + if (blendState.colorMaskRed != mCurBlendState.colorMaskRed || + blendState.colorMaskGreen != mCurBlendState.colorMaskGreen || + blendState.colorMaskBlue != mCurBlendState.colorMaskBlue || + blendState.colorMaskAlpha != mCurBlendState.colorMaskAlpha) + { + mDirtyBits.set(DIRTY_BIT_COLOR_MASK); + + // The color mask can cause the blend state to get out of sync when using the + // zero color mask workaround + if (mUsingZeroColorMaskWorkaround) + { + mDirtyBits.set(DIRTY_BIT_BLEND_ENABLED); + mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS); + } + } + break; + } + case gl::State::DIRTY_BIT_DITHER_ENABLED: + if (state.getBlendState().dither != mCurBlendState.dither) + { + mDirtyBits.set(DIRTY_BIT_DITHER); + } + break; + case gl::State::DIRTY_BIT_BLEND_COLOR: + if (state.getBlendColor() != mCurBlendColor) + { + mDirtyBits.set(DIRTY_BIT_BLEND_COLOR); + } + break; + case gl::State::DIRTY_BIT_CULL_FACE_ENABLED: + if (state.getRasterizerState().cullFace != mCurRasterState.cullFace) + { + mDirtyBits.set(DIRTY_BIT_CULL_MODE); + } + break; + case gl::State::DIRTY_BIT_CULL_FACE: + if (state.getRasterizerState().cullMode != mCurRasterState.cullMode) + { + mDirtyBits.set(DIRTY_BIT_CULL_MODE); + } + break; + case gl::State::DIRTY_BIT_FRONT_FACE: + if (state.getRasterizerState().frontFace != mCurRasterState.frontFace) + { + mDirtyBits.set(DIRTY_BIT_CULL_MODE); + + // Viewport state depends on rasterizer.frontface + mDirtyBits.set(DIRTY_BIT_VIEWPORT); + } + break; + case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED: + if (state.getRasterizerState().polygonOffsetFill != + mCurRasterState.polygonOffsetFill) + { + mDirtyBits.set(DIRTY_BIT_DEPTH_BIAS); + } + break; + case gl::State::DIRTY_BIT_POLYGON_OFFSET: + { + const gl::RasterizerState &rasterizerState = state.getRasterizerState(); + if (rasterizerState.polygonOffsetFactor != mCurRasterState.polygonOffsetFactor || + rasterizerState.polygonOffsetUnits != mCurRasterState.polygonOffsetUnits) + { + mDirtyBits.set(DIRTY_BIT_DEPTH_BIAS); + } + break; + } + case gl::State::DIRTY_BIT_DEPTH_MASK: + if (state.getDepthStencilState().depthMask != mCurDepthStencilState.depthMask) + { + mDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_MASK); + } + break; + case gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED: + if (state.getDepthStencilState().depthTest != mCurDepthStencilState.depthTest) + { + mDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_FUNC); + } + break; + case gl::State::DIRTY_BIT_DEPTH_FUNC: + if (state.getDepthStencilState().depthFunc != mCurDepthStencilState.depthFunc) + { + mDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_FUNC); + } + break; + case gl::State::DIRTY_BIT_STENCIL_TEST_ENABLED: + if (state.getDepthStencilState().stencilTest != mCurDepthStencilState.stencilTest) + { + mDirtyBits.set(DIRTY_BIT_STENCIL_TEST_ENABLED); + // If we enable the stencil test, all of these must be set + mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK); + mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT); + mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_FRONT); + mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_BACK); + mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_FRONT); + mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_BACK); + } + break; + case gl::State::DIRTY_BIT_STENCIL_FUNCS_FRONT: + { + const gl::DepthStencilState &depthStencilState = state.getDepthStencilState(); + if (depthStencilState.stencilFunc != mCurDepthStencilState.stencilFunc || + depthStencilState.stencilMask != mCurDepthStencilState.stencilMask || + state.getStencilRef() != mCurStencilRef) + { + mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_FRONT); + } + break; + } + case gl::State::DIRTY_BIT_STENCIL_FUNCS_BACK: + { + const gl::DepthStencilState &depthStencilState = state.getDepthStencilState(); + if (depthStencilState.stencilBackFunc != mCurDepthStencilState.stencilBackFunc || + depthStencilState.stencilBackMask != mCurDepthStencilState.stencilBackMask || + state.getStencilBackRef() != mCurStencilBackRef) + { + mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_BACK); + } + break; + } + case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT: + if (state.getDepthStencilState().stencilWritemask != + mCurDepthStencilState.stencilWritemask) + { + mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT); + } + break; + case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK: + if (state.getDepthStencilState().stencilBackWritemask != + mCurDepthStencilState.stencilBackWritemask) + { + mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK); + } + break; + case gl::State::DIRTY_BIT_STENCIL_OPS_FRONT: + { + const gl::DepthStencilState &depthStencilState = state.getDepthStencilState(); + if (depthStencilState.stencilFail != mCurDepthStencilState.stencilFail || + depthStencilState.stencilPassDepthFail != + mCurDepthStencilState.stencilPassDepthFail || + depthStencilState.stencilPassDepthPass != + mCurDepthStencilState.stencilPassDepthPass) + { + mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_FRONT); + } + break; + } + case gl::State::DIRTY_BIT_STENCIL_OPS_BACK: + { + const gl::DepthStencilState &depthStencilState = state.getDepthStencilState(); + if (depthStencilState.stencilBackFail != mCurDepthStencilState.stencilBackFail || + depthStencilState.stencilBackPassDepthFail != + mCurDepthStencilState.stencilBackPassDepthFail || + depthStencilState.stencilBackPassDepthPass != + mCurDepthStencilState.stencilBackPassDepthPass) + { + mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_BACK); + } + break; + } + case gl::State::DIRTY_BIT_SCISSOR_TEST_ENABLED: + if (state.isScissorTestEnabled() != mCurScissorEnabled) + { + mDirtyBits.set(DIRTY_BIT_SCISSOR_ENABLED); + // If scissor is enabled, we have to set the scissor rect + mDirtyBits.set(DIRTY_BIT_SCISSOR_RECT); + } + break; + case gl::State::DIRTY_BIT_SCISSOR: + if (state.getScissor() != mCurScissorRect) + { + mDirtyBits.set(DIRTY_BIT_SCISSOR_RECT); + } + break; + case gl::State::DIRTY_BIT_DEPTH_RANGE: + mDirtyBits.set(DIRTY_BIT_VIEWPORT); + break; + case gl::State::DIRTY_BIT_VIEWPORT: + if (state.getViewport() != mCurViewport) + { + mDirtyBits.set(DIRTY_BIT_VIEWPORT); + } + break; + default: + break; + } + } +} + +void StateManager9::setBlendDepthRasterStates(const gl::State &glState, unsigned int sampleMask) +{ + const gl::Framebuffer *framebuffer = glState.getDrawFramebuffer(); + + const gl::BlendState &blendState = glState.getBlendState(); + const gl::ColorF &blendColor = glState.getBlendColor(); + const gl::RasterizerState &rasterState = glState.getRasterizerState(); + + const auto &depthStencilState = glState.getDepthStencilState(); + bool frontFaceCCW = (glState.getRasterizerState().frontFace == GL_CCW); + unsigned int maxStencil = (1 << mCurStencilSize) - 1; + + // All the depth stencil states depends on the front face ccw variable + if (frontFaceCCW != mCurFrontFaceCCW) + { + forceSetDepthStencilState(); + mCurFrontFaceCCW = frontFaceCCW; + } + + for (auto dirtyBit : mDirtyBits) + { + switch (dirtyBit) + { + case DIRTY_BIT_BLEND_ENABLED: + setBlendEnabled(blendState.blend); + break; + case DIRTY_BIT_BLEND_COLOR: + setBlendColor(blendState, blendColor); + break; + case DIRTY_BIT_BLEND_FUNCS_EQUATIONS: + setBlendFuncsEquations(blendState); + break; + case DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE: + setSampleAlphaToCoverage(blendState.sampleAlphaToCoverage); + break; + case DIRTY_BIT_COLOR_MASK: + setColorMask(framebuffer, blendState.colorMaskRed, blendState.colorMaskBlue, + blendState.colorMaskGreen, blendState.colorMaskAlpha); + break; + case DIRTY_BIT_DITHER: + setDither(blendState.dither); + break; + case DIRTY_BIT_CULL_MODE: + setCullMode(rasterState.cullFace, rasterState.cullMode, rasterState.frontFace); + break; + case DIRTY_BIT_DEPTH_BIAS: + setDepthBias(rasterState.polygonOffsetFill, rasterState.polygonOffsetFactor, + rasterState.polygonOffsetUnits); + break; + case DIRTY_BIT_STENCIL_DEPTH_MASK: + setDepthMask(depthStencilState.depthMask); + break; + case DIRTY_BIT_STENCIL_DEPTH_FUNC: + setDepthFunc(depthStencilState.depthTest, depthStencilState.depthFunc); + break; + case DIRTY_BIT_STENCIL_TEST_ENABLED: + setStencilTestEnabled(depthStencilState.stencilTest); + break; + case DIRTY_BIT_STENCIL_FUNCS_FRONT: + setStencilFuncsFront(depthStencilState.stencilFunc, depthStencilState.stencilMask, + glState.getStencilRef(), frontFaceCCW, maxStencil); + break; + case DIRTY_BIT_STENCIL_FUNCS_BACK: + setStencilFuncsBack(depthStencilState.stencilBackFunc, + depthStencilState.stencilBackMask, glState.getStencilBackRef(), + frontFaceCCW, maxStencil); + break; + case DIRTY_BIT_STENCIL_WRITEMASK_FRONT: + setStencilWriteMask(depthStencilState.stencilWritemask, frontFaceCCW); + break; + case DIRTY_BIT_STENCIL_WRITEMASK_BACK: + setStencilBackWriteMask(depthStencilState.stencilBackWritemask, frontFaceCCW); + break; + case DIRTY_BIT_STENCIL_OPS_FRONT: + setStencilOpsFront(depthStencilState.stencilFail, + depthStencilState.stencilPassDepthFail, + depthStencilState.stencilPassDepthPass, frontFaceCCW); + break; + case DIRTY_BIT_STENCIL_OPS_BACK: + setStencilOpsBack(depthStencilState.stencilBackFail, + depthStencilState.stencilBackPassDepthFail, + depthStencilState.stencilBackPassDepthPass, frontFaceCCW); + break; + default: + break; + } + } + + if (sampleMask != mCurSampleMask) + { + setSampleMask(sampleMask); + } +} + +void StateManager9::setViewportState(const gl::Rectangle &viewport, + float zNear, + float zFar, + gl::PrimitiveMode drawMode, + GLenum frontFace, + bool ignoreViewport) +{ + if (!mDirtyBits.test(DIRTY_BIT_VIEWPORT) && mCurIgnoreViewport == ignoreViewport) + return; + + gl::Rectangle actualViewport = viewport; + float actualZNear = gl::clamp01(zNear); + float actualZFar = gl::clamp01(zFar); + + if (ignoreViewport) + { + actualViewport.x = 0; + actualViewport.y = 0; + actualViewport.width = static_cast<int>(mRenderTargetBounds.width); + actualViewport.height = static_cast<int>(mRenderTargetBounds.height); + actualZNear = 0.0f; + actualZFar = 1.0f; + } + + D3DVIEWPORT9 dxViewport; + dxViewport.X = gl::clamp(actualViewport.x, 0, static_cast<int>(mRenderTargetBounds.width)); + dxViewport.Y = gl::clamp(actualViewport.y, 0, static_cast<int>(mRenderTargetBounds.height)); + dxViewport.Width = + gl::clamp(actualViewport.width, 0, + static_cast<int>(mRenderTargetBounds.width) - static_cast<int>(dxViewport.X)); + dxViewport.Height = + gl::clamp(actualViewport.height, 0, + static_cast<int>(mRenderTargetBounds.height) - static_cast<int>(dxViewport.Y)); + dxViewport.MinZ = actualZNear; + dxViewport.MaxZ = actualZFar; + + float depthFront = !gl::IsTriangleMode(drawMode) ? 0.0f : (frontFace == GL_CCW ? 1.0f : -1.0f); + + mRenderer9->getDevice()->SetViewport(&dxViewport); + + mCurViewport = actualViewport; + mCurNear = actualZNear; + mCurFar = actualZFar; + mCurDepthFront = depthFront; + mCurIgnoreViewport = ignoreViewport; + + // Setting shader constants + dx_VertexConstants9 vc = {}; + dx_PixelConstants9 pc = {}; + + vc.viewAdjust[0] = + static_cast<float>((actualViewport.width - static_cast<int>(dxViewport.Width)) + + 2 * (actualViewport.x - static_cast<int>(dxViewport.X)) - 1) / + dxViewport.Width; + vc.viewAdjust[1] = + static_cast<float>((actualViewport.height - static_cast<int>(dxViewport.Height)) + + 2 * (actualViewport.y - static_cast<int>(dxViewport.Y)) - 1) / + dxViewport.Height; + vc.viewAdjust[2] = static_cast<float>(actualViewport.width) / dxViewport.Width; + vc.viewAdjust[3] = static_cast<float>(actualViewport.height) / dxViewport.Height; + + pc.viewCoords[0] = actualViewport.width * 0.5f; + pc.viewCoords[1] = actualViewport.height * 0.5f; + pc.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f); + pc.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f); + + pc.depthFront[0] = (actualZFar - actualZNear) * 0.5f; + pc.depthFront[1] = (actualZNear + actualZFar) * 0.5f; + pc.depthFront[2] = depthFront; + + vc.depthRange[0] = actualZNear; + vc.depthRange[1] = actualZFar; + vc.depthRange[2] = actualZFar - actualZNear; + + pc.depthRange[0] = actualZNear; + pc.depthRange[1] = actualZFar; + pc.depthRange[2] = actualZFar - actualZNear; + + if (memcmp(&vc, &mVertexConstants, sizeof(dx_VertexConstants9)) != 0) + { + mVertexConstants = vc; + mDxUniformsDirty = true; + } + + if (memcmp(&pc, &mPixelConstants, sizeof(dx_PixelConstants9)) != 0) + { + mPixelConstants = pc; + mDxUniformsDirty = true; + } + + mForceSetViewport = false; +} + +void StateManager9::setShaderConstants() +{ + if (!mDxUniformsDirty) + return; + + IDirect3DDevice9 *device = mRenderer9->getDevice(); + device->SetVertexShaderConstantF(0, reinterpret_cast<float *>(&mVertexConstants), + sizeof(dx_VertexConstants9) / sizeof(float[4])); + device->SetPixelShaderConstantF(0, reinterpret_cast<float *>(&mPixelConstants), + sizeof(dx_PixelConstants9) / sizeof(float[4])); + mDxUniformsDirty = false; +} + +// This is separate from the main state loop because other functions +// outside call only setScissorState to update scissor state +void StateManager9::setScissorState(const gl::Rectangle &scissor, bool enabled) +{ + if (mDirtyBits.test(DIRTY_BIT_SCISSOR_ENABLED)) + setScissorEnabled(enabled); + + if (mDirtyBits.test(DIRTY_BIT_SCISSOR_RECT)) + setScissorRect(scissor, enabled); +} + +void StateManager9::setRenderTargetBounds(size_t width, size_t height) +{ + mRenderTargetBounds.width = (int)width; + mRenderTargetBounds.height = (int)height; + forceSetViewportState(); +} + +void StateManager9::setScissorEnabled(bool scissorEnabled) +{ + mRenderer9->getDevice()->SetRenderState(D3DRS_SCISSORTESTENABLE, scissorEnabled ? TRUE : FALSE); + mCurScissorEnabled = scissorEnabled; +} + +void StateManager9::setScissorRect(const gl::Rectangle &scissor, bool enabled) +{ + if (!enabled) + return; + + RECT rect; + rect.left = gl::clamp(scissor.x, 0, static_cast<int>(mRenderTargetBounds.width)); + rect.top = gl::clamp(scissor.y, 0, static_cast<int>(mRenderTargetBounds.height)); + rect.right = + gl::clamp(scissor.x + scissor.width, 0, static_cast<int>(mRenderTargetBounds.width)); + rect.bottom = + gl::clamp(scissor.y + scissor.height, 0, static_cast<int>(mRenderTargetBounds.height)); + mRenderer9->getDevice()->SetScissorRect(&rect); +} + +void StateManager9::setDepthFunc(bool depthTest, GLenum depthFunc) +{ + if (depthTest) + { + IDirect3DDevice9 *device = mRenderer9->getDevice(); + device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); + device->SetRenderState(D3DRS_ZFUNC, gl_d3d9::ConvertComparison(depthFunc)); + } + else + { + mRenderer9->getDevice()->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + } + + mCurDepthStencilState.depthTest = depthTest; + mCurDepthStencilState.depthFunc = depthFunc; +} + +void StateManager9::setStencilOpsFront(GLenum stencilFail, + GLenum stencilPassDepthFail, + GLenum stencilPassDepthPass, + bool frontFaceCCW) +{ + // TODO(dianx) It may be slightly more efficient todo these and other similar areas + // with separate dirty bits. + IDirect3DDevice9 *device = mRenderer9->getDevice(); + device->SetRenderState(frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, + gl_d3d9::ConvertStencilOp(stencilFail)); + device->SetRenderState(frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, + gl_d3d9::ConvertStencilOp(stencilPassDepthFail)); + device->SetRenderState(frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, + gl_d3d9::ConvertStencilOp(stencilPassDepthPass)); + + mCurDepthStencilState.stencilFail = stencilFail; + mCurDepthStencilState.stencilPassDepthFail = stencilPassDepthFail; + mCurDepthStencilState.stencilPassDepthPass = stencilPassDepthPass; +} + +void StateManager9::setStencilOpsBack(GLenum stencilBackFail, + GLenum stencilBackPassDepthFail, + GLenum stencilBackPassDepthPass, + bool frontFaceCCW) +{ + IDirect3DDevice9 *device = mRenderer9->getDevice(); + device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, + gl_d3d9::ConvertStencilOp(stencilBackFail)); + device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, + gl_d3d9::ConvertStencilOp(stencilBackPassDepthFail)); + device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, + gl_d3d9::ConvertStencilOp(stencilBackPassDepthPass)); + + mCurDepthStencilState.stencilBackFail = stencilBackFail; + mCurDepthStencilState.stencilBackPassDepthFail = stencilBackPassDepthFail; + mCurDepthStencilState.stencilBackPassDepthPass = stencilBackPassDepthPass; +} + +void StateManager9::setStencilBackWriteMask(GLuint stencilBackWriteMask, bool frontFaceCCW) +{ + mRenderer9->getDevice()->SetRenderState( + !frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, stencilBackWriteMask); + + mCurDepthStencilState.stencilBackWritemask = stencilBackWriteMask; +} + +void StateManager9::setStencilFuncsBack(GLenum stencilBackFunc, + GLuint stencilBackMask, + GLint stencilBackRef, + bool frontFaceCCW, + unsigned int maxStencil) +{ + IDirect3DDevice9 *device = mRenderer9->getDevice(); + device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, + gl_d3d9::ConvertComparison(stencilBackFunc)); + device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, + (stencilBackRef < (int)maxStencil) ? stencilBackRef : maxStencil); + device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, + stencilBackMask); + + mCurDepthStencilState.stencilBackFunc = stencilBackFunc; + mCurStencilBackRef = stencilBackRef; + mCurDepthStencilState.stencilBackMask = stencilBackMask; +} + +void StateManager9::setStencilWriteMask(GLuint stencilWriteMask, bool frontFaceCCW) +{ + mRenderer9->getDevice()->SetRenderState( + frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, stencilWriteMask); + mCurDepthStencilState.stencilWritemask = stencilWriteMask; +} + +void StateManager9::setStencilFuncsFront(GLenum stencilFunc, + GLuint stencilMask, + GLint stencilRef, + bool frontFaceCCW, + unsigned int maxStencil) +{ + IDirect3DDevice9 *device = mRenderer9->getDevice(); + device->SetRenderState(frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, + gl_d3d9::ConvertComparison(stencilFunc)); + device->SetRenderState(frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, + (stencilRef < static_cast<int>(maxStencil)) ? stencilRef : maxStencil); + device->SetRenderState(frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, stencilMask); + + mCurDepthStencilState.stencilFunc = stencilFunc; + mCurStencilRef = stencilRef; + mCurDepthStencilState.stencilMask = stencilMask; +} +void StateManager9::setStencilTestEnabled(bool stencilTestEnabled) +{ + if (stencilTestEnabled && mCurStencilSize > 0) + { + mRenderer9->getDevice()->SetRenderState(D3DRS_STENCILENABLE, TRUE); + mRenderer9->getDevice()->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE); + } + else + { + mRenderer9->getDevice()->SetRenderState(D3DRS_STENCILENABLE, FALSE); + } + + mCurDepthStencilState.stencilTest = stencilTestEnabled; +} + +void StateManager9::setDepthMask(bool depthMask) +{ + mRenderer9->getDevice()->SetRenderState(D3DRS_ZWRITEENABLE, depthMask ? TRUE : FALSE); + mCurDepthStencilState.depthMask = depthMask; +} + +// TODO(dianx) one bit for sampleAlphaToCoverage +void StateManager9::setSampleAlphaToCoverage(bool enabled) +{ + if (enabled) + { + UNREACHABLE(); + } +} + +void StateManager9::setBlendColor(const gl::BlendState &blendState, const gl::ColorF &blendColor) +{ + if (!blendState.blend) + return; + + if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA && + blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA && + blendState.destBlendRGB != GL_CONSTANT_ALPHA && + blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA) + { + mRenderer9->getDevice()->SetRenderState(D3DRS_BLENDFACTOR, + gl_d3d9::ConvertColor(blendColor)); + } + else + { + mRenderer9->getDevice()->SetRenderState( + D3DRS_BLENDFACTOR, + D3DCOLOR_RGBA(gl::unorm<8>(blendColor.alpha), gl::unorm<8>(blendColor.alpha), + gl::unorm<8>(blendColor.alpha), gl::unorm<8>(blendColor.alpha))); + } + mCurBlendColor = blendColor; +} + +void StateManager9::setBlendFuncsEquations(const gl::BlendState &blendState) +{ + if (!blendState.blend) + return; + + IDirect3DDevice9 *device = mRenderer9->getDevice(); + + device->SetRenderState(D3DRS_SRCBLEND, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendRGB)); + device->SetRenderState(D3DRS_DESTBLEND, gl_d3d9::ConvertBlendFunc(blendState.destBlendRGB)); + device->SetRenderState(D3DRS_BLENDOP, gl_d3d9::ConvertBlendOp(blendState.blendEquationRGB)); + + if (blendState.sourceBlendRGB != blendState.sourceBlendAlpha || + blendState.destBlendRGB != blendState.destBlendAlpha || + blendState.blendEquationRGB != blendState.blendEquationAlpha) + { + device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + + device->SetRenderState(D3DRS_SRCBLENDALPHA, + gl_d3d9::ConvertBlendFunc(blendState.sourceBlendAlpha)); + device->SetRenderState(D3DRS_DESTBLENDALPHA, + gl_d3d9::ConvertBlendFunc(blendState.destBlendAlpha)); + device->SetRenderState(D3DRS_BLENDOPALPHA, + gl_d3d9::ConvertBlendOp(blendState.blendEquationAlpha)); + } + else + { + device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); + } + + mCurBlendState.sourceBlendRGB = blendState.sourceBlendRGB; + mCurBlendState.destBlendRGB = blendState.destBlendRGB; + mCurBlendState.blendEquationRGB = blendState.blendEquationRGB; + mCurBlendState.blendEquationAlpha = blendState.blendEquationAlpha; +} + +void StateManager9::setBlendEnabled(bool enabled) +{ + mRenderer9->getDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE, enabled ? TRUE : FALSE); + mCurBlendState.blend = enabled; +} + +void StateManager9::setDither(bool dither) +{ + mRenderer9->getDevice()->SetRenderState(D3DRS_DITHERENABLE, dither ? TRUE : FALSE); + mCurBlendState.dither = dither; +} + +// TODO(dianx) one bit for color mask +void StateManager9::setColorMask(const gl::Framebuffer *framebuffer, + bool red, + bool blue, + bool green, + bool alpha) +{ + // Set the color mask + + const auto *attachment = framebuffer->getFirstColorAttachment(); + const auto &format = attachment ? attachment->getFormat() : gl::Format::Invalid(); + + DWORD colorMask = gl_d3d9::ConvertColorMask( + format.info->redBits > 0 && red, format.info->greenBits > 0 && green, + format.info->blueBits > 0 && blue, format.info->alphaBits > 0 && alpha); + + // Apparently some ATI cards have a bug where a draw with a zero color write mask can cause + // later draws to have incorrect results. Instead, set a nonzero color write mask but modify the + // blend state so that no drawing is done. + // http://anglebug.com/169 + if (colorMask == 0 && mUsingZeroColorMaskWorkaround) + { + IDirect3DDevice9 *device = mRenderer9->getDevice(); + // Enable green channel, but set blending so nothing will be drawn. + device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN); + + device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + + device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); + device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + + mCurBlendState.colorMaskRed = false; + mCurBlendState.colorMaskGreen = true; + mCurBlendState.colorMaskBlue = false; + mCurBlendState.colorMaskAlpha = false; + + mCurBlendState.blend = true; + mCurBlendState.sourceBlendRGB = GL_ZERO; + mCurBlendState.sourceBlendAlpha = GL_ZERO; + mCurBlendState.destBlendRGB = GL_ONE; + mCurBlendState.destBlendAlpha = GL_ONE; + mCurBlendState.blendEquationRGB = GL_FUNC_ADD; + mCurBlendState.blendEquationAlpha = GL_FUNC_ADD; + } + else + { + mRenderer9->getDevice()->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask); + + mCurBlendState.colorMaskRed = red; + mCurBlendState.colorMaskGreen = green; + mCurBlendState.colorMaskBlue = blue; + mCurBlendState.colorMaskAlpha = alpha; + } +} + +void StateManager9::setSampleMask(unsigned int sampleMask) +{ + IDirect3DDevice9 *device = mRenderer9->getDevice(); + // Set the multisample mask + device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); + device->SetRenderState(D3DRS_MULTISAMPLEMASK, static_cast<DWORD>(sampleMask)); + + mCurSampleMask = sampleMask; +} + +void StateManager9::setCullMode(bool cullFace, gl::CullFaceMode cullMode, GLenum frontFace) +{ + if (cullFace) + { + mRenderer9->getDevice()->SetRenderState(D3DRS_CULLMODE, + gl_d3d9::ConvertCullMode(cullMode, frontFace)); + } + else + { + mRenderer9->getDevice()->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + } + + mCurRasterState.cullFace = cullFace; + mCurRasterState.cullMode = cullMode; + mCurRasterState.frontFace = frontFace; +} + +void StateManager9::setDepthBias(bool polygonOffsetFill, + GLfloat polygonOffsetFactor, + GLfloat polygonOffsetUnits) +{ + if (polygonOffsetFill) + { + if (mCurDepthSize > 0) + { + IDirect3DDevice9 *device = mRenderer9->getDevice(); + device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD *)&polygonOffsetFactor); + + float depthBias = ldexp(polygonOffsetUnits, -static_cast<int>(mCurDepthSize)); + device->SetRenderState(D3DRS_DEPTHBIAS, *(DWORD *)&depthBias); + } + } + else + { + IDirect3DDevice9 *device = mRenderer9->getDevice(); + device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0); + device->SetRenderState(D3DRS_DEPTHBIAS, 0); + } + + mCurRasterState.polygonOffsetFill = polygonOffsetFill; + mCurRasterState.polygonOffsetFactor = polygonOffsetFactor; + mCurRasterState.polygonOffsetUnits = polygonOffsetUnits; +} + +void StateManager9::updateDepthSizeIfChanged(bool depthStencilInitialized, unsigned int depthSize) +{ + if (!depthStencilInitialized || depthSize != mCurDepthSize) + { + mCurDepthSize = depthSize; + forceSetRasterState(); + } +} +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/StateManager9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/StateManager9.h new file mode 100644 index 0000000000..2457303731 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/StateManager9.h @@ -0,0 +1,209 @@ +// +// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// StateManager9.h: Defines a class for caching D3D9 state + +#ifndef LIBANGLE_RENDERER_D3D9_STATEMANAGER9_H_ +#define LIBANGLE_RENDERER_D3D9_STATEMANAGER9_H_ + +#include "libANGLE/State.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" + +namespace rx +{ + +class Renderer9; + +struct dx_VertexConstants9 +{ + float depthRange[4]; + float viewAdjust[4]; + float viewCoords[4]; +}; + +struct dx_PixelConstants9 +{ + float depthRange[4]; + float viewCoords[4]; + float depthFront[4]; +}; + +class StateManager9 final : angle::NonCopyable +{ + public: + StateManager9(Renderer9 *renderer9); + ~StateManager9(); + + void initialize(); + + void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits); + + void setBlendDepthRasterStates(const gl::State &glState, unsigned int sampleMask); + void setScissorState(const gl::Rectangle &scissor, bool enabled); + void setViewportState(const gl::Rectangle &viewport, + float zNear, + float zFar, + gl::PrimitiveMode drawMode, + GLenum frontFace, + bool ignoreViewport); + + void setShaderConstants(); + + void forceSetBlendState(); + void forceSetRasterState(); + void forceSetDepthStencilState(); + void forceSetScissorState(); + void forceSetViewportState(); + void forceSetDXUniformsState(); + + void updateDepthSizeIfChanged(bool depthStencilInitialized, unsigned int depthSize); + void updateStencilSizeIfChanged(bool depthStencilInitialized, unsigned int stencilSize); + + void setRenderTargetBounds(size_t width, size_t height); + + int getRenderTargetWidth() const { return mRenderTargetBounds.width; } + int getRenderTargetHeight() const { return mRenderTargetBounds.height; } + + void setAllDirtyBits() { mDirtyBits.set(); } + void resetDirtyBits() { mDirtyBits.reset(); } + + private: + // Blend state functions + void setBlendEnabled(bool enabled); + void setBlendColor(const gl::BlendState &blendState, const gl::ColorF &blendColor); + void setBlendFuncsEquations(const gl::BlendState &blendState); + void setColorMask(const gl::Framebuffer *framebuffer, + bool red, + bool blue, + bool green, + bool alpha); + void setSampleAlphaToCoverage(bool enabled); + void setDither(bool dither); + void setSampleMask(unsigned int sampleMask); + + // Current raster state functions + void setCullMode(bool cullFace, gl::CullFaceMode cullMode, GLenum frontFace); + void setDepthBias(bool polygonOffsetFill, + GLfloat polygonOffsetFactor, + GLfloat polygonOffsetUnits); + + // Depth stencil state functions + void setStencilOpsFront(GLenum stencilFail, + GLenum stencilPassDepthFail, + GLenum stencilPassDepthPass, + bool frontFaceCCW); + void setStencilOpsBack(GLenum stencilBackFail, + GLenum stencilBackPassDepthFail, + GLenum stencilBackPassDepthPass, + bool frontFaceCCW); + void setStencilBackWriteMask(GLuint stencilBackWriteMask, bool frontFaceCCW); + void setDepthFunc(bool depthTest, GLenum depthFunc); + void setStencilTestEnabled(bool enabled); + void setDepthMask(bool depthMask); + void setStencilFuncsFront(GLenum stencilFunc, + GLuint stencilMask, + GLint stencilRef, + bool frontFaceCCW, + unsigned int maxStencil); + void setStencilFuncsBack(GLenum stencilBackFunc, + GLuint stencilBackMask, + GLint stencilBackRef, + bool frontFaceCCW, + unsigned int maxStencil); + void setStencilWriteMask(GLuint stencilWriteMask, bool frontFaceCCW); + + void setScissorEnabled(bool scissorEnabled); + void setScissorRect(const gl::Rectangle &scissor, bool enabled); + + enum DirtyBitType + { + // Blend dirty bits + DIRTY_BIT_BLEND_ENABLED, + DIRTY_BIT_BLEND_COLOR, + DIRTY_BIT_BLEND_FUNCS_EQUATIONS, + DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE, + DIRTY_BIT_COLOR_MASK, + DIRTY_BIT_DITHER, + DIRTY_BIT_SAMPLE_MASK, + + // Rasterizer dirty bits + DIRTY_BIT_CULL_MODE, + DIRTY_BIT_DEPTH_BIAS, + + // Depth stencil dirty bits + DIRTY_BIT_STENCIL_DEPTH_MASK, + DIRTY_BIT_STENCIL_DEPTH_FUNC, + DIRTY_BIT_STENCIL_TEST_ENABLED, + DIRTY_BIT_STENCIL_FUNCS_FRONT, + DIRTY_BIT_STENCIL_FUNCS_BACK, + DIRTY_BIT_STENCIL_WRITEMASK_FRONT, + DIRTY_BIT_STENCIL_WRITEMASK_BACK, + DIRTY_BIT_STENCIL_OPS_FRONT, + DIRTY_BIT_STENCIL_OPS_BACK, + + // Scissor dirty bits + DIRTY_BIT_SCISSOR_ENABLED, + DIRTY_BIT_SCISSOR_RECT, + + // Viewport dirty bits + DIRTY_BIT_VIEWPORT, + + DIRTY_BIT_MAX + }; + + using DirtyBits = angle::BitSet<DIRTY_BIT_MAX>; + + bool mUsingZeroColorMaskWorkaround; + + // Currently applied blend state + gl::BlendState mCurBlendState; + gl::ColorF mCurBlendColor; + unsigned int mCurSampleMask; + DirtyBits mBlendStateDirtyBits; + + // Currently applied raster state + gl::RasterizerState mCurRasterState; + unsigned int mCurDepthSize; + DirtyBits mRasterizerStateDirtyBits; + + // Currently applied depth stencil state + gl::DepthStencilState mCurDepthStencilState; + int mCurStencilRef; + int mCurStencilBackRef; + bool mCurFrontFaceCCW; + unsigned int mCurStencilSize; + DirtyBits mDepthStencilStateDirtyBits; + + // Currently applied scissor states + gl::Rectangle mCurScissorRect; + bool mCurScissorEnabled; + gl::Extents mRenderTargetBounds; + DirtyBits mScissorStateDirtyBits; + + // Currently applied viewport states + bool mForceSetViewport; + gl::Rectangle mCurViewport; + float mCurNear; + float mCurFar; + float mCurDepthFront; + bool mCurIgnoreViewport; + + dx_VertexConstants9 mVertexConstants; + dx_PixelConstants9 mPixelConstants; + bool mDxUniformsDirty; + + // FIXME: Unsupported by D3D9 + static const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF; + static const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK; + static const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK; + + Renderer9 *mRenderer9; + DirtyBits mDirtyBits; +}; + +} // namespace rx +#endif // LIBANGLE_RENDERER_D3D9_STATEMANAGER9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp new file mode 100644 index 0000000000..bb6e7a186e --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp @@ -0,0 +1,472 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SwapChain9.cpp: Implements a back-end specific class for the D3D9 swap chain. + +#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h" + +#include "libANGLE/features.h" +#include "libANGLE/renderer/d3d/d3d9/NativeWindow9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" + +namespace rx +{ + +SwapChain9::SwapChain9(Renderer9 *renderer, + NativeWindow9 *nativeWindow, + HANDLE shareHandle, + IUnknown *d3dTexture, + GLenum backBufferFormat, + GLenum depthBufferFormat, + EGLint orientation) + : SwapChainD3D(shareHandle, d3dTexture, backBufferFormat, depthBufferFormat), + mRenderer(renderer), + mWidth(-1), + mHeight(-1), + mSwapInterval(-1), + mNativeWindow(nativeWindow), + mSwapChain(nullptr), + mBackBuffer(nullptr), + mRenderTarget(nullptr), + mDepthStencil(nullptr), + mOffscreenTexture(nullptr), + mColorRenderTarget(this, false), + mDepthStencilRenderTarget(this, true) +{ + ASSERT(orientation == 0); +} + +SwapChain9::~SwapChain9() +{ + release(); +} + +void SwapChain9::release() +{ + SafeRelease(mSwapChain); + SafeRelease(mBackBuffer); + SafeRelease(mDepthStencil); + SafeRelease(mRenderTarget); + SafeRelease(mOffscreenTexture); + + if (mNativeWindow->getNativeWindow()) + { + mShareHandle = nullptr; + } +} + +static DWORD convertInterval(EGLint interval) +{ +#if ANGLE_VSYNC == ANGLE_DISABLED + return D3DPRESENT_INTERVAL_IMMEDIATE; +#else + switch (interval) + { + case 0: + return D3DPRESENT_INTERVAL_IMMEDIATE; + case 1: + return D3DPRESENT_INTERVAL_ONE; + case 2: + return D3DPRESENT_INTERVAL_TWO; + case 3: + return D3DPRESENT_INTERVAL_THREE; + case 4: + return D3DPRESENT_INTERVAL_FOUR; + default: + UNREACHABLE(); + } + + return D3DPRESENT_INTERVAL_DEFAULT; +#endif +} + +EGLint SwapChain9::resize(DisplayD3D *displayD3D, int backbufferWidth, int backbufferHeight) +{ + // D3D9 does not support resizing swap chains without recreating them + return reset(displayD3D, backbufferWidth, backbufferHeight, mSwapInterval); +} + +EGLint SwapChain9::reset(DisplayD3D *displayD3D, + int backbufferWidth, + int backbufferHeight, + EGLint swapInterval) +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + if (device == nullptr) + { + return EGL_BAD_ACCESS; + } + + // Evict all non-render target textures to system memory and release all resources + // before reallocating them to free up as much video memory as possible. + device->EvictManagedResources(); + + HRESULT result; + + // Release specific resources to free up memory for the new render target, while the + // old render target still exists for the purpose of preserving its contents. + SafeRelease(mSwapChain); + SafeRelease(mBackBuffer); + SafeRelease(mOffscreenTexture); + SafeRelease(mDepthStencil); + + const d3d9::TextureFormat &backBufferd3dFormatInfo = + d3d9::GetTextureFormatInfo(mOffscreenRenderTargetFormat); + if (mD3DTexture != nullptr) + { + result = mD3DTexture->QueryInterface(&mOffscreenTexture); + ASSERT(SUCCEEDED(result)); + } + else + { + HANDLE *pShareHandle = nullptr; + if (!mNativeWindow->getNativeWindow() && mRenderer->getShareHandleSupport()) + { + pShareHandle = &mShareHandle; + } + + result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET, + backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT, + &mOffscreenTexture, pShareHandle); + if (FAILED(result)) + { + ERR() << "Could not create offscreen texture, " << gl::FmtHR(result); + release(); + + if (d3d9::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + } + + IDirect3DSurface9 *oldRenderTarget = mRenderTarget; + + result = mOffscreenTexture->GetSurfaceLevel(0, &mRenderTarget); + ASSERT(SUCCEEDED(result)); + + if (oldRenderTarget) + { + RECT rect = {0, 0, mWidth, mHeight}; + + if (rect.right > static_cast<LONG>(backbufferWidth)) + { + rect.right = backbufferWidth; + } + + if (rect.bottom > static_cast<LONG>(backbufferHeight)) + { + rect.bottom = backbufferHeight; + } + + mRenderer->endScene(); + + result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE); + ASSERT(SUCCEEDED(result)); + + SafeRelease(oldRenderTarget); + } + + const d3d9::TextureFormat &depthBufferd3dFormatInfo = + d3d9::GetTextureFormatInfo(mDepthBufferFormat); + + // Don't create a swapchain for NULLREF devices + D3DDEVTYPE deviceType = mRenderer->getD3D9DeviceType(); + EGLNativeWindowType window = mNativeWindow->getNativeWindow(); + if (window && deviceType != D3DDEVTYPE_NULLREF) + { + D3DPRESENT_PARAMETERS presentParameters = {0}; + presentParameters.AutoDepthStencilFormat = depthBufferd3dFormatInfo.renderFormat; + presentParameters.BackBufferCount = 1; + presentParameters.BackBufferFormat = backBufferd3dFormatInfo.renderFormat; + presentParameters.EnableAutoDepthStencil = FALSE; + presentParameters.Flags = 0; + presentParameters.hDeviceWindow = window; + presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented + presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented + presentParameters.PresentationInterval = convertInterval(swapInterval); + presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; + presentParameters.Windowed = TRUE; + presentParameters.BackBufferWidth = backbufferWidth; + presentParameters.BackBufferHeight = backbufferHeight; + + // http://crbug.com/140239 + // http://crbug.com/143434 + // + // Some AMD/Intel switchable systems / drivers appear to round swap chain surfaces to a + // multiple of 64 pixels in width when using the integrated Intel. This rounds the width up + // rather than down. + // + // Some non-switchable AMD GPUs / drivers do not respect the source rectangle to Present. + // Therefore, when the vendor ID is not Intel, the back buffer width must be exactly the + // same width as the window or horizontal scaling will occur. + if (IsIntel(mRenderer->getVendorId())) + { + presentParameters.BackBufferWidth = (presentParameters.BackBufferWidth + 63) / 64 * 64; + } + + result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || + result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST); + + ERR() << "Could not create additional swap chains or offscreen surfaces, " + << gl::FmtHR(result); + release(); + + if (d3d9::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + + result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); + ASSERT(SUCCEEDED(result)); + InvalidateRect(window, nullptr, FALSE); + } + + if (mDepthBufferFormat != GL_NONE) + { + result = device->CreateDepthStencilSurface( + backbufferWidth, backbufferHeight, depthBufferd3dFormatInfo.renderFormat, + D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, nullptr); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || + result == D3DERR_INVALIDCALL); + + ERR() << "Could not create depthstencil surface for new swap chain, " + << gl::FmtHR(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(DisplayD3D *displayD3D, EGLint x, EGLint y, EGLint width, EGLint height) +{ + if (!mSwapChain) + { + return EGL_SUCCESS; + } + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + // Disable all pipeline operations + device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + device->SetRenderState(D3DRS_STENCILENABLE, FALSE); + device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + device->SetRenderState(D3DRS_COLORWRITEENABLE, + D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | + D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE); + device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + device->SetPixelShader(nullptr); + device->SetVertexShader(nullptr); + + device->SetRenderTarget(0, mBackBuffer); + device->SetDepthStencilSurface(nullptr); + + device->SetTexture(0, mOffscreenTexture); + device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + + for (UINT streamIndex = 0; streamIndex < gl::MAX_VERTEX_ATTRIBS; streamIndex++) + { + device->SetStreamSourceFreq(streamIndex, 1); + } + + D3DVIEWPORT9 viewport = {0, 0, static_cast<DWORD>(mWidth), static_cast<DWORD>(mHeight), + 0.0f, 1.0f}; + device->SetViewport(&viewport); + + float x1 = x - 0.5f; + float y1 = (mHeight - y - height) - 0.5f; + float x2 = (x + width) - 0.5f; + float y2 = (mHeight - y) - 0.5f; + + float u1 = x / float(mWidth); + float v1 = y / float(mHeight); + float u2 = (x + width) / float(mWidth); + float v2 = (y + height) / float(mHeight); + + float quad[4][6] = {{x1, y1, 0.0f, 1.0f, u1, v2}, + {x2, y1, 0.0f, 1.0f, u2, v2}, + {x2, y2, 0.0f, 1.0f, u2, v1}, + {x1, y2, 0.0f, 1.0f, u1, v1}}; // x, y, z, rhw, u, v + + mRenderer->startScene(); + device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float)); + mRenderer->endScene(); + + device->SetTexture(0, nullptr); + + RECT rect = {static_cast<LONG>(x), static_cast<LONG>(mHeight - y - height), + static_cast<LONG>(x + width), static_cast<LONG>(mHeight - y)}; + + HRESULT result = mSwapChain->Present(&rect, &rect, nullptr, nullptr, 0); + + mRenderer->markAllStateDirty(); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || + result == D3DERR_DRIVERINTERNALERROR) + { + return EGL_BAD_ALLOC; + } + + // On Windows 8 systems, IDirect3DSwapChain9::Present sometimes returns 0x88760873 when the + // windows is in the process of entering/exiting fullscreen. This code doesn't seem to have any + // documentation. The device appears to be ok after emitting this error so simply return a + // failure to swap. + if (result == static_cast<HRESULT>(0x88760873) || result == static_cast<HRESULT>(0x88760872)) + { + return EGL_BAD_MATCH; + } + + // http://crbug.com/313210 + // If our swap failed, trigger a device lost event. Resetting will work around an AMD-specific + // device removed bug with lost contexts when reinstalling drivers. + if (FAILED(result)) + { + mRenderer->notifyDeviceLost(); + return EGL_CONTEXT_LOST; + } + + return EGL_SUCCESS; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +// TODO: remove the AddRef to match SwapChain11 +IDirect3DSurface9 *SwapChain9::getRenderTarget() +{ + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + return mRenderTarget; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +// TODO: remove the AddRef to match SwapChain11 +IDirect3DSurface9 *SwapChain9::getDepthStencil() +{ + if (mDepthStencil) + { + mDepthStencil->AddRef(); + } + + return mDepthStencil; +} + +// Increments refcount on texture. +// caller must Release() the returned texture +// TODO: remove the AddRef to match SwapChain11 +IDirect3DTexture9 *SwapChain9::getOffscreenTexture() +{ + if (mOffscreenTexture) + { + mOffscreenTexture->AddRef(); + } + + return mOffscreenTexture; +} + +void *SwapChain9::getKeyedMutex() +{ + UNREACHABLE(); + return nullptr; +} + +egl::Error SwapChain9::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) +{ + UNREACHABLE(); + return egl::EglBadSurface(); +} + +void SwapChain9::recreate() +{ + if (!mSwapChain) + { + return; + } + + IDirect3DDevice9 *device = mRenderer->getDevice(); + if (device == nullptr) + { + return; + } + + D3DPRESENT_PARAMETERS presentParameters; + HRESULT result = mSwapChain->GetPresentParameters(&presentParameters); + ASSERT(SUCCEEDED(result)); + + IDirect3DSwapChain9 *newSwapChain = nullptr; + 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)); +} + +RenderTargetD3D *SwapChain9::getColorRenderTarget() +{ + return &mColorRenderTarget; +} + +RenderTargetD3D *SwapChain9::getDepthStencilRenderTarget() +{ + return &mDepthStencilRenderTarget; +} +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h new file mode 100644 index 0000000000..c4c9843a74 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h @@ -0,0 +1,80 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SwapChain9.h: Defines a back-end specific class for the D3D9 swap chain. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_SWAPCHAIN9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_SWAPCHAIN9_H_ + +#include "common/angleutils.h" +#include "libANGLE/renderer/d3d/SwapChainD3D.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" + +namespace rx +{ +class NativeWindow9; +class Renderer9; + +class SwapChain9 : public SwapChainD3D +{ + public: + SwapChain9(Renderer9 *renderer, + NativeWindow9 *nativeWindow, + HANDLE shareHandle, + IUnknown *d3dTexture, + GLenum backBufferFormat, + GLenum depthBufferFormat, + EGLint orientation); + ~SwapChain9() override; + + EGLint resize(DisplayD3D *displayD3D, EGLint backbufferWidth, EGLint backbufferHeight) override; + EGLint reset(DisplayD3D *displayD3D, + EGLint backbufferWidth, + EGLint backbufferHeight, + EGLint swapInterval) override; + EGLint swapRect(DisplayD3D *displayD3D, + EGLint x, + EGLint y, + EGLint width, + EGLint height) override; + void recreate() override; + + RenderTargetD3D *getColorRenderTarget() override; + RenderTargetD3D *getDepthStencilRenderTarget() override; + + virtual IDirect3DSurface9 *getRenderTarget(); + virtual IDirect3DSurface9 *getDepthStencil(); + virtual IDirect3DTexture9 *getOffscreenTexture(); + + EGLint getWidth() const { return mWidth; } + EGLint getHeight() const { return mHeight; } + + void *getKeyedMutex() override; + + egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override; + + private: + void release(); + + Renderer9 *mRenderer; + EGLint mWidth; + EGLint mHeight; + EGLint mSwapInterval; + + NativeWindow9 *mNativeWindow; + + IDirect3DSwapChain9 *mSwapChain; + IDirect3DSurface9 *mBackBuffer; + IDirect3DSurface9 *mRenderTarget; + IDirect3DSurface9 *mDepthStencil; + IDirect3DTexture9 *mOffscreenTexture; + + SurfaceRenderTarget9 mColorRenderTarget; + SurfaceRenderTarget9 mDepthStencilRenderTarget; +}; + +} // namespace rx +#endif // LIBANGLE_RENDERER_D3D_D3D9_SWAPCHAIN9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp new file mode 100644 index 0000000000..fabb773dc0 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp @@ -0,0 +1,523 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureStorage9.cpp: Implements the abstract rx::TextureStorage9 class and its concrete derived +// classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the +// D3D9 texture. + +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" + +#include "common/utilities.h" +#include "libANGLE/Context.h" +#include "libANGLE/Texture.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/EGLImageD3D.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" + +namespace rx +{ +TextureStorage9::TextureStorage9(Renderer9 *renderer, DWORD usage) + : mTopLevel(0), + mMipLevels(0), + mTextureWidth(0), + mTextureHeight(0), + mInternalFormat(GL_NONE), + mTextureFormat(D3DFMT_UNKNOWN), + mRenderer(renderer), + mD3DUsage(usage), + mD3DPool(mRenderer->getTexturePool(usage)) +{} + +TextureStorage9::~TextureStorage9() {} + +DWORD TextureStorage9::GetTextureUsage(GLenum internalformat, bool renderTarget) +{ + DWORD d3dusage = 0; + + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalformat); + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + d3dusage |= D3DUSAGE_DEPTHSTENCIL; + } + else if (renderTarget && (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN)) + { + d3dusage |= D3DUSAGE_RENDERTARGET; + } + + return d3dusage; +} + +bool TextureStorage9::isRenderTarget() const +{ + return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0; +} + +bool TextureStorage9::isManaged() const +{ + return (mD3DPool == D3DPOOL_MANAGED); +} + +bool TextureStorage9::supportsNativeMipmapFunction() const +{ + return false; +} + +D3DPOOL TextureStorage9::getPool() const +{ + return mD3DPool; +} + +DWORD TextureStorage9::getUsage() const +{ + return mD3DUsage; +} + +int TextureStorage9::getTopLevel() const +{ + return mTopLevel; +} + +int TextureStorage9::getLevelCount() const +{ + return static_cast<int>(mMipLevels) - mTopLevel; +} + +angle::Result TextureStorage9::setData(const gl::Context *context, + const gl::ImageIndex &index, + ImageD3D *image, + const gl::Box *destBox, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixelData) +{ + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); + return angle::Result::Stop; +} + +TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain) + : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET) +{ + IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture(); + mTexture = surfaceTexture; + mMipLevels = surfaceTexture->GetLevelCount(); + + mInternalFormat = swapchain->getRenderTargetInternalFormat(); + + D3DSURFACE_DESC surfaceDesc; + surfaceTexture->GetLevelDesc(0, &surfaceDesc); + mTextureWidth = surfaceDesc.Width; + mTextureHeight = surfaceDesc.Height; + mTextureFormat = surfaceDesc.Format; + + mRenderTargets.resize(mMipLevels, nullptr); +} + +TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, + GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + int levels) + : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) +{ + mTexture = nullptr; + + mInternalFormat = internalformat; + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); + mTextureFormat = d3dFormatInfo.texFormat; + + d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &width, &height, &mTopLevel); + mTextureWidth = width; + mTextureHeight = height; + mMipLevels = mTopLevel + levels; + + mRenderTargets.resize(levels, nullptr); +} + +TextureStorage9_2D::~TextureStorage9_2D() +{ + SafeRelease(mTexture); + for (RenderTargetD3D *renderTarget : mRenderTargets) + { + SafeDelete(renderTarget); + } +} + +// Increments refcount on surface. +// caller must Release() the returned surface +angle::Result TextureStorage9_2D::getSurfaceLevel(const gl::Context *context, + gl::TextureTarget target, + int level, + bool dirty, + IDirect3DSurface9 **outSurface) +{ + ASSERT(target == gl::TextureTarget::_2D); + + IDirect3DBaseTexture9 *baseTexture = nullptr; + ANGLE_TRY(getBaseTexture(context, &baseTexture)); + + IDirect3DTexture9 *texture = static_cast<IDirect3DTexture9 *>(baseTexture); + + HRESULT result = texture->GetSurfaceLevel(level + mTopLevel, outSurface); + ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to get the surface from a texture"); + + // With managed textures the driver needs to be informed of updates to the lower mipmap levels + if (level + mTopLevel != 0 && isManaged() && dirty) + { + texture->AddDirtyRect(nullptr); + } + + return angle::Result::Continue; +} + +angle::Result TextureStorage9_2D::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) +{ + ASSERT(index.getLevelIndex() < getLevelCount()); + + if (!mRenderTargets[index.getLevelIndex()] && isRenderTarget()) + { + IDirect3DBaseTexture9 *baseTexture = nullptr; + ANGLE_TRY(getBaseTexture(context, &baseTexture)); + + IDirect3DSurface9 *surface = nullptr; + ANGLE_TRY(getSurfaceLevel(context, gl::TextureTarget::_2D, index.getLevelIndex(), false, + &surface)); + + size_t textureMipLevel = mTopLevel + index.getLevelIndex(); + size_t mipWidth = std::max<size_t>(mTextureWidth >> textureMipLevel, 1u); + size_t mipHeight = std::max<size_t>(mTextureHeight >> textureMipLevel, 1u); + + baseTexture->AddRef(); + mRenderTargets[index.getLevelIndex()] = new TextureRenderTarget9( + baseTexture, textureMipLevel, surface, mInternalFormat, static_cast<GLsizei>(mipWidth), + static_cast<GLsizei>(mipHeight), 1, 0); + } + + ASSERT(outRT); + *outRT = mRenderTargets[index.getLevelIndex()]; + return angle::Result::Continue; +} + +angle::Result TextureStorage9_2D::generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) +{ + angle::ComPtr<IDirect3DSurface9> upper = nullptr; + ANGLE_TRY(getSurfaceLevel(context, gl::TextureTarget::_2D, sourceIndex.getLevelIndex(), false, + &upper)); + + angle::ComPtr<IDirect3DSurface9> lower = nullptr; + ANGLE_TRY( + getSurfaceLevel(context, gl::TextureTarget::_2D, destIndex.getLevelIndex(), true, &lower)); + + ASSERT(upper && lower); + return mRenderer->boxFilter(GetImplAs<Context9>(context), upper.Get(), lower.Get()); +} + +angle::Result TextureStorage9_2D::getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) +{ + // if the width or height is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (mTexture == nullptr && mTextureWidth > 0 && mTextureHeight > 0) + { + ASSERT(mMipLevels > 0); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + HRESULT result = device->CreateTexture(static_cast<unsigned int>(mTextureWidth), + static_cast<unsigned int>(mTextureHeight), + static_cast<unsigned int>(mMipLevels), getUsage(), + mTextureFormat, getPool(), &mTexture, nullptr); + ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to create 2D storage texture"); + } + + *outTexture = mTexture; + return angle::Result::Continue; +} + +angle::Result TextureStorage9_2D::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) +{ + ASSERT(destStorage); + + TextureStorage9_2D *dest9 = GetAs<TextureStorage9_2D>(destStorage); + + int levels = getLevelCount(); + for (int i = 0; i < levels; ++i) + { + angle::ComPtr<IDirect3DSurface9> srcSurf = nullptr; + ANGLE_TRY(getSurfaceLevel(context, gl::TextureTarget::_2D, i, false, &srcSurf)); + + angle::ComPtr<IDirect3DSurface9> dstSurf = nullptr; + ANGLE_TRY(dest9->getSurfaceLevel(context, gl::TextureTarget::_2D, i, true, &dstSurf)); + + ANGLE_TRY( + mRenderer->copyToRenderTarget(context, dstSurf.Get(), srcSurf.Get(), isManaged())); + } + + return angle::Result::Continue; +} + +TextureStorage9_EGLImage::TextureStorage9_EGLImage(Renderer9 *renderer, + EGLImageD3D *image, + RenderTarget9 *renderTarget9) + : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET), mImage(image) +{ + mInternalFormat = renderTarget9->getInternalFormat(); + mTextureFormat = renderTarget9->getD3DFormat(); + mTextureWidth = renderTarget9->getWidth(); + mTextureHeight = renderTarget9->getHeight(); + mTopLevel = static_cast<int>(renderTarget9->getTextureLevel()); + mMipLevels = mTopLevel + 1; +} + +TextureStorage9_EGLImage::~TextureStorage9_EGLImage() {} + +angle::Result TextureStorage9_EGLImage::getSurfaceLevel(const gl::Context *context, + gl::TextureTarget target, + int level, + bool, + IDirect3DSurface9 **outSurface) +{ + ASSERT(target == gl::TextureTarget::_2D); + ASSERT(level == 0); + + RenderTargetD3D *renderTargetD3D = nullptr; + ANGLE_TRY(mImage->getRenderTarget(context, &renderTargetD3D)); + + RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTargetD3D); + + *outSurface = renderTarget9->getSurface(); + return angle::Result::Continue; +} + +angle::Result TextureStorage9_EGLImage::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) +{ + ASSERT(!index.hasLayer()); + ASSERT(index.getLevelIndex() == 0); + + return mImage->getRenderTarget(context, outRT); +} + +angle::Result TextureStorage9_EGLImage::getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) +{ + RenderTargetD3D *renderTargetD3D = nullptr; + ANGLE_TRY(mImage->getRenderTarget(context, &renderTargetD3D)); + + RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTargetD3D); + *outTexture = renderTarget9->getTexture(); + ASSERT(*outTexture != nullptr); + + return angle::Result::Continue; +} + +angle::Result TextureStorage9_EGLImage::generateMipmap(const gl::Context *context, + const gl::ImageIndex &, + const gl::ImageIndex &) +{ + ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); + return angle::Result::Stop; +} + +angle::Result TextureStorage9_EGLImage::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) +{ + ASSERT(destStorage); + ASSERT(getLevelCount() == 1); + + TextureStorage9 *dest9 = GetAs<TextureStorage9>(destStorage); + + IDirect3DBaseTexture9 *destBaseTexture9 = nullptr; + ANGLE_TRY(dest9->getBaseTexture(context, &destBaseTexture9)); + + IDirect3DTexture9 *destTexture9 = static_cast<IDirect3DTexture9 *>(destBaseTexture9); + + angle::ComPtr<IDirect3DSurface9> destSurface = nullptr; + HRESULT result = destTexture9->GetSurfaceLevel(destStorage->getTopLevel(), &destSurface); + ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to get the surface from a texture"); + + RenderTargetD3D *sourceRenderTarget = nullptr; + ANGLE_TRY(mImage->getRenderTarget(context, &sourceRenderTarget)); + + RenderTarget9 *sourceRenderTarget9 = GetAs<RenderTarget9>(sourceRenderTarget); + ANGLE_TRY(mRenderer->copyToRenderTarget(context, destSurface.Get(), + sourceRenderTarget9->getSurface(), isManaged())); + + if (destStorage->getTopLevel() != 0) + { + destTexture9->AddDirtyRect(nullptr); + } + + return angle::Result::Continue; +} + +TextureStorage9_Cube::TextureStorage9_Cube(Renderer9 *renderer, + GLenum internalformat, + bool renderTarget, + int size, + int levels, + bool hintLevelZeroOnly) + : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) +{ + mTexture = nullptr; + for (size_t i = 0; i < gl::kCubeFaceCount; ++i) + { + mRenderTarget[i] = nullptr; + } + + mInternalFormat = internalformat; + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); + mTextureFormat = d3dFormatInfo.texFormat; + + int height = size; + d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &size, &height, &mTopLevel); + mTextureWidth = size; + mTextureHeight = size; + mMipLevels = mTopLevel + levels; +} + +TextureStorage9_Cube::~TextureStorage9_Cube() +{ + SafeRelease(mTexture); + + for (size_t i = 0; i < gl::kCubeFaceCount; ++i) + { + SafeDelete(mRenderTarget[i]); + } +} + +// Increments refcount on surface. +// caller must Release() the returned surface +angle::Result TextureStorage9_Cube::getSurfaceLevel(const gl::Context *context, + gl::TextureTarget target, + int level, + bool dirty, + IDirect3DSurface9 **outSurface) +{ + IDirect3DBaseTexture9 *baseTexture = nullptr; + ANGLE_TRY(getBaseTexture(context, &baseTexture)); + + IDirect3DCubeTexture9 *texture = static_cast<IDirect3DCubeTexture9 *>(baseTexture); + + D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(target); + HRESULT result = texture->GetCubeMapSurface(face, level, outSurface); + ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to get the surface from a texture"); + + // With managed textures the driver needs to be informed of updates to the lower mipmap levels + if (level != 0 && isManaged() && dirty) + { + texture->AddDirtyRect(face, nullptr); + } + + return angle::Result::Continue; +} + +angle::Result TextureStorage9_Cube::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) +{ + ASSERT(outRT); + ASSERT(index.getLevelIndex() == 0); + + ASSERT(index.getType() == gl::TextureType::CubeMap && + gl::IsCubeMapFaceTarget(index.getTarget())); + const size_t renderTargetIndex = index.cubeMapFaceIndex(); + + if (mRenderTarget[renderTargetIndex] == nullptr && isRenderTarget()) + { + IDirect3DBaseTexture9 *baseTexture = nullptr; + ANGLE_TRY(getBaseTexture(context, &baseTexture)); + + IDirect3DSurface9 *surface = nullptr; + ANGLE_TRY(getSurfaceLevel(context, index.getTarget(), mTopLevel + index.getLevelIndex(), + false, &surface)); + + baseTexture->AddRef(); + mRenderTarget[renderTargetIndex] = new TextureRenderTarget9( + baseTexture, mTopLevel + index.getLevelIndex(), surface, mInternalFormat, + static_cast<GLsizei>(mTextureWidth), static_cast<GLsizei>(mTextureHeight), 1, 0); + } + + *outRT = mRenderTarget[renderTargetIndex]; + return angle::Result::Continue; +} + +angle::Result TextureStorage9_Cube::generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) +{ + angle::ComPtr<IDirect3DSurface9> upper = nullptr; + ANGLE_TRY(getSurfaceLevel(context, sourceIndex.getTarget(), sourceIndex.getLevelIndex(), false, + &upper)); + + angle::ComPtr<IDirect3DSurface9> lower = nullptr; + ANGLE_TRY( + getSurfaceLevel(context, destIndex.getTarget(), destIndex.getLevelIndex(), true, &lower)); + + ASSERT(upper && lower); + return mRenderer->boxFilter(GetImplAs<Context9>(context), upper.Get(), lower.Get()); +} + +angle::Result TextureStorage9_Cube::getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) +{ + // if the size is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (mTexture == nullptr && mTextureWidth > 0 && mTextureHeight > 0) + { + ASSERT(mMipLevels > 0); + ASSERT(mTextureWidth == mTextureHeight); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + HRESULT result = device->CreateCubeTexture( + static_cast<unsigned int>(mTextureWidth), static_cast<unsigned int>(mMipLevels), + getUsage(), mTextureFormat, getPool(), &mTexture, nullptr); + ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to create cube storage texture"); + } + + *outTexture = mTexture; + return angle::Result::Continue; +} + +angle::Result TextureStorage9_Cube::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) +{ + ASSERT(destStorage); + + TextureStorage9_Cube *dest9 = GetAs<TextureStorage9_Cube>(destStorage); + + int levels = getLevelCount(); + for (gl::TextureTarget face : gl::AllCubeFaceTextureTargets()) + { + for (int i = 0; i < levels; i++) + { + angle::ComPtr<IDirect3DSurface9> srcSurf = nullptr; + ANGLE_TRY(getSurfaceLevel(context, face, i, false, &srcSurf)); + + angle::ComPtr<IDirect3DSurface9> dstSurf = nullptr; + ANGLE_TRY(dest9->getSurfaceLevel(context, face, i, true, &dstSurf)); + + ANGLE_TRY( + mRenderer->copyToRenderTarget(context, dstSurf.Get(), srcSurf.Get(), isManaged())); + } + } + + return angle::Result::Continue; +} +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h new file mode 100644 index 0000000000..7228cf68f0 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h @@ -0,0 +1,164 @@ +// +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureStorage9.h: Defines the abstract rx::TextureStorage9 class and its concrete derived +// classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the +// D3D9 texture. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_TEXTURESTORAGE9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_TEXTURESTORAGE9_H_ + +#include "common/debug.h" +#include "libANGLE/renderer/d3d/TextureStorage.h" + +namespace rx +{ +class EGLImageD3D; +class Renderer9; +class SwapChain9; +class RenderTargetD3D; +class RenderTarget9; + +class TextureStorage9 : public TextureStorage +{ + public: + ~TextureStorage9() override; + + static DWORD GetTextureUsage(GLenum internalformat, bool renderTarget); + + D3DPOOL getPool() const; + DWORD getUsage() const; + + virtual angle::Result getSurfaceLevel(const gl::Context *context, + gl::TextureTarget target, + int level, + bool dirty, + IDirect3DSurface9 **outSurface) = 0; + virtual angle::Result getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) = 0; + + int getTopLevel() const override; + bool isRenderTarget() const override; + bool isManaged() const override; + bool supportsNativeMipmapFunction() const override; + int getLevelCount() const override; + + angle::Result setData(const gl::Context *context, + const gl::ImageIndex &index, + ImageD3D *image, + const gl::Box *destBox, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixelData) override; + + protected: + int mTopLevel; + size_t mMipLevels; + size_t mTextureWidth; + size_t mTextureHeight; + GLenum mInternalFormat; + D3DFORMAT mTextureFormat; + + Renderer9 *mRenderer; + + TextureStorage9(Renderer9 *renderer, DWORD usage); + + private: + const DWORD mD3DUsage; + const D3DPOOL mD3DPool; +}; + +class TextureStorage9_2D : public TextureStorage9 +{ + public: + TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain); + TextureStorage9_2D(Renderer9 *renderer, + GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + int levels); + ~TextureStorage9_2D() override; + + angle::Result getSurfaceLevel(const gl::Context *context, + gl::TextureTarget target, + int level, + bool dirty, + IDirect3DSurface9 **outSurface) override; + angle::Result getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + angle::Result getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) override; + angle::Result generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) override; + angle::Result copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; + + private: + IDirect3DTexture9 *mTexture; + std::vector<RenderTarget9 *> mRenderTargets; +}; + +class TextureStorage9_EGLImage final : public TextureStorage9 +{ + public: + TextureStorage9_EGLImage(Renderer9 *renderer, EGLImageD3D *image, RenderTarget9 *renderTarget9); + ~TextureStorage9_EGLImage() override; + + angle::Result getSurfaceLevel(const gl::Context *context, + gl::TextureTarget target, + int level, + bool dirty, + IDirect3DSurface9 **outSurface) override; + angle::Result getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + angle::Result getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) override; + angle::Result generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) override; + angle::Result copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; + + private: + EGLImageD3D *mImage; +}; + +class TextureStorage9_Cube : public TextureStorage9 +{ + public: + TextureStorage9_Cube(Renderer9 *renderer, + GLenum internalformat, + bool renderTarget, + int size, + int levels, + bool hintLevelZeroOnly); + ~TextureStorage9_Cube() override; + + angle::Result getSurfaceLevel(const gl::Context *context, + gl::TextureTarget target, + int level, + bool dirty, + IDirect3DSurface9 **outSurface) override; + angle::Result getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + angle::Result getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) override; + angle::Result generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) override; + angle::Result copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; + + private: + IDirect3DCubeTexture9 *mTexture; + RenderTarget9 *mRenderTarget[gl::kCubeFaceCount]; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_TEXTURESTORAGE9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h new file mode 100644 index 0000000000..a9c1ee7d4b --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h @@ -0,0 +1,57 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexArray9.h: Defines the rx::VertexArray9 class which implements rx::VertexArrayImpl. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ + +#include "libANGLE/Context.h" +#include "libANGLE/renderer/VertexArrayImpl.h" +#include "libANGLE/renderer/d3d/d3d9/Context9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ +class Renderer9; + +class VertexArray9 : public VertexArrayImpl +{ + public: + VertexArray9(const gl::VertexArrayState &data) : VertexArrayImpl(data) {} + + angle::Result syncState(const gl::Context *context, + const gl::VertexArray::DirtyBits &dirtyBits, + gl::VertexArray::DirtyAttribBitsArray *attribBits, + gl::VertexArray::DirtyBindingBitsArray *bindingBits) override; + + ~VertexArray9() override {} + + Serial getCurrentStateSerial() const { return mCurrentStateSerial; } + + private: + Serial mCurrentStateSerial; +}; + +inline angle::Result VertexArray9::syncState(const gl::Context *context, + const gl::VertexArray::DirtyBits &dirtyBits, + gl::VertexArray::DirtyAttribBitsArray *attribBits, + gl::VertexArray::DirtyBindingBitsArray *bindingBits) +{ + + ASSERT(dirtyBits.any()); + Renderer9 *renderer = GetImplAs<Context9>(context)->getRenderer(); + mCurrentStateSerial = renderer->generateSerial(); + + // Clear the dirty bits in the back-end here. + memset(attribBits, 0, sizeof(gl::VertexArray::DirtyAttribBitsArray)); + memset(bindingBits, 0, sizeof(gl::VertexArray::DirtyBindingBitsArray)); + + return angle::Result::Continue; +} +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp new file mode 100644 index 0000000000..67517f2788 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp @@ -0,0 +1,153 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexBuffer9.cpp: Defines the D3D9 VertexBuffer implementation. + +#include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h" + +#include "libANGLE/Buffer.h" +#include "libANGLE/Context.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/vertexconversion.h" + +namespace rx +{ + +VertexBuffer9::VertexBuffer9(Renderer9 *renderer) : mRenderer(renderer) +{ + mVertexBuffer = nullptr; + mBufferSize = 0; + mDynamicUsage = false; +} + +VertexBuffer9::~VertexBuffer9() +{ + SafeRelease(mVertexBuffer); +} + +angle::Result VertexBuffer9::initialize(const gl::Context *context, + 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); + ANGLE_TRY_HR(GetImplAs<Context9>(context), result, + "Failed to allocate internal vertex buffer"); + } + + mBufferSize = size; + mDynamicUsage = dynamicUsage; + return angle::Result::Continue; +} + +angle::Result VertexBuffer9::storeVertexAttributes(const gl::Context *context, + const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + gl::VertexAttribType currentValueType, + GLint start, + size_t count, + GLsizei instances, + unsigned int offset, + const uint8_t *sourceData) +{ + ASSERT(mVertexBuffer); + + size_t inputStride = gl::ComputeVertexAttributeStride(attrib, binding); + size_t elementSize = gl::ComputeVertexAttributeTypeSize(attrib); + + DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0; + + uint8_t *mapPtr = nullptr; + + unsigned int mapSize = 0; + ANGLE_TRY( + mRenderer->getVertexSpaceRequired(context, attrib, binding, count, instances, &mapSize)); + + HRESULT result = + mVertexBuffer->Lock(offset, mapSize, reinterpret_cast<void **>(&mapPtr), lockFlags); + ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to lock internal vertex buffer"); + + const uint8_t *input = sourceData; + + if (instances == 0 || binding.getDivisor() == 0) + { + input += inputStride * start; + } + + angle::FormatID vertexFormatID = gl::GetVertexFormatID(attrib, currentValueType); + const d3d9::VertexFormat &d3dVertexInfo = + d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormatID); + bool needsConversion = (d3dVertexInfo.conversionType & VERTEX_CONVERT_CPU) > 0; + + if (!needsConversion && inputStride == elementSize) + { + size_t copySize = count * inputStride; + memcpy(mapPtr, input, copySize); + } + else + { + d3dVertexInfo.copyFunction(input, inputStride, count, mapPtr); + } + + mVertexBuffer->Unlock(); + + return angle::Result::Continue; +} + +unsigned int VertexBuffer9::getBufferSize() const +{ + return mBufferSize; +} + +angle::Result VertexBuffer9::setBufferSize(const gl::Context *context, unsigned int size) +{ + if (size > mBufferSize) + { + return initialize(context, size, mDynamicUsage); + } + else + { + return angle::Result::Continue; + } +} + +angle::Result VertexBuffer9::discard(const gl::Context *context) +{ + ASSERT(mVertexBuffer); + + void *dummy; + HRESULT result; + + Context9 *context9 = GetImplAs<Context9>(context); + + result = mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); + ANGLE_TRY_HR(context9, result, "Failed to lock internal vertex buffer for discarding"); + + result = mVertexBuffer->Unlock(); + ANGLE_TRY_HR(context9, result, "Failed to unlock internal vertex buffer for discarding"); + + return angle::Result::Continue; +} + +IDirect3DVertexBuffer9 *VertexBuffer9::getBuffer() const +{ + return mVertexBuffer; +} +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h new file mode 100644 index 0000000000..178a7a3f6a --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h @@ -0,0 +1,56 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexBuffer9.h: Defines the D3D9 VertexBuffer implementation. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXBUFFER9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXBUFFER9_H_ + +#include "libANGLE/renderer/d3d/VertexBuffer.h" + +namespace rx +{ +class Renderer9; + +class VertexBuffer9 : public VertexBuffer +{ + public: + explicit VertexBuffer9(Renderer9 *renderer); + + angle::Result initialize(const gl::Context *context, + unsigned int size, + bool dynamicUsage) override; + + // Warning: you should ensure binding really matches attrib.bindingIndex before using this + // function. + angle::Result storeVertexAttributes(const gl::Context *context, + const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + gl::VertexAttribType currentValueType, + GLint start, + size_t count, + GLsizei instances, + unsigned int offset, + const uint8_t *sourceData) override; + + unsigned int getBufferSize() const override; + angle::Result setBufferSize(const gl::Context *context, unsigned int size) override; + angle::Result discard(const gl::Context *context) override; + + IDirect3DVertexBuffer9 *getBuffer() const; + + private: + ~VertexBuffer9() override; + Renderer9 *mRenderer; + + IDirect3DVertexBuffer9 *mVertexBuffer; + unsigned int mBufferSize; + bool mDynamicUsage; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXBUFFER9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp new file mode 100644 index 0000000000..c7c642404e --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp @@ -0,0 +1,262 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexDeclarationCache.cpp: Implements a helper class to construct and cache vertex declarations. + +#include "libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h" + +#include "libANGLE/Context.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" +#include "libANGLE/renderer/d3d/d3d9/Context9.h" +#include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" + +namespace rx +{ + +VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0) +{ + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + mVertexDeclCache[i].vertexDeclaration = nullptr; + mVertexDeclCache[i].lruCount = 0; + } + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mAppliedVBs[i].serial = 0; + } + + mLastSetVDecl = nullptr; + mInstancingEnabled = true; +} + +VertexDeclarationCache::~VertexDeclarationCache() +{ + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + SafeRelease(mVertexDeclCache[i].vertexDeclaration); + } +} + +angle::Result VertexDeclarationCache::applyDeclaration( + const gl::Context *context, + IDirect3DDevice9 *device, + const std::vector<TranslatedAttribute> &attributes, + gl::Program *program, + GLint start, + GLsizei instances, + GLsizei *repeatDraw) +{ + ASSERT(gl::MAX_VERTEX_ATTRIBS >= attributes.size()); + + *repeatDraw = 1; + + const size_t invalidAttribIndex = attributes.size(); + size_t indexedAttribute = invalidAttribIndex; + size_t instancedAttribute = invalidAttribIndex; + + if (instances == 0) + { + for (size_t i = 0; i < attributes.size(); ++i) + { + if (attributes[i].divisor != 0) + { + // If a divisor is set, it still applies even if an instanced draw was not used, so + // treat as a single-instance draw. + instances = 1; + break; + } + } + } + + if (instances > 0) + { + // Find an indexed attribute to be mapped to D3D stream 0 + for (size_t i = 0; i < attributes.size(); i++) + { + if (attributes[i].active) + { + if (indexedAttribute == invalidAttribIndex && attributes[i].divisor == 0) + { + indexedAttribute = i; + } + else if (instancedAttribute == invalidAttribIndex && attributes[i].divisor != 0) + { + instancedAttribute = i; + } + if (indexedAttribute != invalidAttribIndex && + instancedAttribute != invalidAttribIndex) + break; // Found both an indexed and instanced attribute + } + } + + // The validation layer checks that there is at least one active attribute with a zero + // divisor as per the GL_ANGLE_instanced_arrays spec. + ASSERT(indexedAttribute != invalidAttribIndex); + } + + D3DCAPS9 caps; + device->GetDeviceCaps(&caps); + + D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1]; + D3DVERTEXELEMENT9 *element = &elements[0]; + + ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program); + const auto &semanticIndexes = programD3D->getAttribLocationToD3DSemantics(); + + for (size_t i = 0; i < attributes.size(); i++) + { + if (attributes[i].active) + { + // Directly binding the storage buffer is not supported for d3d9 + ASSERT(attributes[i].storage == nullptr); + + int stream = static_cast<int>(i); + + if (instances > 0) + { + // Due to a bug on ATI cards we can't enable instancing when none of the attributes + // are instanced. + if (instancedAttribute == invalidAttribIndex) + { + *repeatDraw = instances; + } + else + { + if (i == indexedAttribute) + { + stream = 0; + } + else if (i == 0) + { + stream = static_cast<int>(indexedAttribute); + } + + UINT frequency = 1; + + if (attributes[i].divisor == 0) + { + frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances; + } + else + { + frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor; + } + + device->SetStreamSourceFreq(stream, frequency); + mInstancingEnabled = true; + } + } + + VertexBuffer9 *vertexBuffer = GetAs<VertexBuffer9>(attributes[i].vertexBuffer.get()); + + unsigned int offset = 0; + ANGLE_TRY(attributes[i].computeOffset(context, start, &offset)); + + if (mAppliedVBs[stream].serial != attributes[i].serial || + mAppliedVBs[stream].stride != attributes[i].stride || + mAppliedVBs[stream].offset != offset) + { + device->SetStreamSource(stream, vertexBuffer->getBuffer(), offset, + attributes[i].stride); + mAppliedVBs[stream].serial = attributes[i].serial; + mAppliedVBs[stream].stride = attributes[i].stride; + mAppliedVBs[stream].offset = offset; + } + + angle::FormatID vertexformatID = + gl::GetVertexFormatID(*attributes[i].attribute, gl::VertexAttribType::Float); + const d3d9::VertexFormat &d3d9VertexInfo = + d3d9::GetVertexFormatInfo(caps.DeclTypes, vertexformatID); + + element->Stream = static_cast<WORD>(stream); + element->Offset = 0; + element->Type = static_cast<BYTE>(d3d9VertexInfo.nativeFormat); + element->Method = D3DDECLMETHOD_DEFAULT; + element->Usage = D3DDECLUSAGE_TEXCOORD; + element->UsageIndex = static_cast<BYTE>(semanticIndexes[i]); + element++; + } + } + + if (instances == 0 || instancedAttribute == invalidAttribIndex) + { + if (mInstancingEnabled) + { + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + device->SetStreamSourceFreq(i, 1); + } + + mInstancingEnabled = false; + } + } + + static const D3DVERTEXELEMENT9 end = D3DDECL_END(); + *(element++) = end; + + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + VertexDeclCacheEntry *entry = &mVertexDeclCache[i]; + if (memcmp(entry->cachedElements, elements, + (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 && + entry->vertexDeclaration) + { + entry->lruCount = ++mMaxLru; + if (entry->vertexDeclaration != mLastSetVDecl) + { + device->SetVertexDeclaration(entry->vertexDeclaration); + mLastSetVDecl = entry->vertexDeclaration; + } + + return angle::Result::Continue; + } + } + + 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 != nullptr) + { + 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); + ANGLE_TRY_HR(GetImplAs<Context9>(context), result, + "Failed to create internal vertex declaration"); + + device->SetVertexDeclaration(lastCache->vertexDeclaration); + mLastSetVDecl = lastCache->vertexDeclaration; + lastCache->lruCount = ++mMaxLru; + + return angle::Result::Continue; +} + +void VertexDeclarationCache::markStateDirty() +{ + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mAppliedVBs[i].serial = 0; + } + + mLastSetVDecl = nullptr; + mInstancingEnabled = true; // Forces it to be disabled when not used +} + +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h new file mode 100644 index 0000000000..53667f1ff8 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h @@ -0,0 +1,68 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexDeclarationCache.h: Defines a helper class to construct and cache vertex declarations. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXDECLARATIONCACHE_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXDECLARATIONCACHE_H_ + +#include "libANGLE/Error.h" +#include "libANGLE/renderer/d3d/VertexDataManager.h" + +namespace gl +{ +class VertexDataManager; +class Program; +} // namespace gl + +namespace rx +{ +class VertexDeclarationCache +{ + public: + VertexDeclarationCache(); + ~VertexDeclarationCache(); + + angle::Result applyDeclaration(const gl::Context *context, + IDirect3DDevice9 *device, + const std::vector<TranslatedAttribute> &attributes, + gl::Program *program, + GLint start, + GLsizei instances, + GLsizei *repeatDraw); + + void markStateDirty(); + + private: + UINT mMaxLru; + + enum + { + NUM_VERTEX_DECL_CACHE_ENTRIES = 32 + }; + + struct VBData + { + unsigned int serial; + unsigned int stride; + unsigned int offset; + }; + + VBData mAppliedVBs[gl::MAX_VERTEX_ATTRIBS]; + IDirect3DVertexDeclaration9 *mLastSetVDecl; + bool mInstancingEnabled; + + struct VertexDeclCacheEntry + { + D3DVERTEXELEMENT9 cachedElements[gl::MAX_VERTEX_ATTRIBS + 1]; + UINT lruCount; + IDirect3DVertexDeclaration9 *vertexDeclaration; + } mVertexDeclCache[NUM_VERTEX_DECL_CACHE_ENTRIES]; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXDECLARATIONCACHE_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp new file mode 100644 index 0000000000..826b446953 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp @@ -0,0 +1,872 @@ +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils9.cpp: Queries for GL image formats and their translations to D3D9 +// formats. + +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" + +#include "image_util/copyimage.h" +#include "image_util/generatemip.h" +#include "image_util/loadimage.h" + +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/vertexconversion.h" + +using namespace angle; + +namespace rx +{ + +namespace d3d9 +{ + +constexpr D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Z'))); +constexpr D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N', 'U', 'L', 'L'))); + +// A map to determine the pixel size and mip generation function of a given D3D format +typedef std::map<D3DFORMAT, D3DFormat> D3D9FormatInfoMap; + +D3DFormat::D3DFormat() + : pixelBytes(0), + blockWidth(0), + blockHeight(0), + redBits(0), + greenBits(0), + blueBits(0), + alphaBits(0), + luminanceBits(0), + depthBits(0), + stencilBits(0), + formatID(angle::FormatID::NONE) +{} + +D3DFormat::D3DFormat(GLuint bits, + GLuint blockWidth, + GLuint blockHeight, + GLuint redBits, + GLuint greenBits, + GLuint blueBits, + GLuint alphaBits, + GLuint lumBits, + GLuint depthBits, + GLuint stencilBits, + FormatID formatID) + : pixelBytes(bits / 8), + blockWidth(blockWidth), + blockHeight(blockHeight), + redBits(redBits), + greenBits(greenBits), + blueBits(blueBits), + alphaBits(alphaBits), + luminanceBits(lumBits), + depthBits(depthBits), + stencilBits(stencilBits), + formatID(formatID) +{} + +const D3DFormat &GetD3DFormatInfo(D3DFORMAT format) +{ + if (format == D3DFMT_NULL) + { + static const D3DFormat info(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FormatID::NONE); + return info; + } + + if (format == D3DFMT_INTZ) + { + static const D3DFormat info(32, 1, 1, 0, 0, 0, 0, 0, 24, 8, FormatID::D24_UNORM_S8_UINT); + return info; + } + + switch (format) + { + case D3DFMT_UNKNOWN: + { + static const D3DFormat info(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FormatID::NONE); + return info; + } + + case D3DFMT_L8: + { + static const D3DFormat info(8, 1, 1, 0, 0, 0, 0, 8, 0, 0, FormatID::L8_UNORM); + return info; + } + case D3DFMT_A8: + { + static const D3DFormat info(8, 1, 1, 0, 0, 0, 8, 0, 0, 0, FormatID::A8_UNORM); + return info; + } + case D3DFMT_A8L8: + { + static const D3DFormat info(16, 1, 1, 0, 0, 0, 8, 8, 0, 0, FormatID::L8A8_UNORM); + return info; + } + + case D3DFMT_A4R4G4B4: + { + static const D3DFormat info(16, 1, 1, 4, 4, 4, 4, 0, 0, 0, FormatID::B4G4R4A4_UNORM); + return info; + } + case D3DFMT_A1R5G5B5: + { + static const D3DFormat info(16, 1, 1, 5, 5, 5, 1, 0, 0, 0, FormatID::B5G5R5A1_UNORM); + return info; + } + case D3DFMT_R5G6B5: + { + static const D3DFormat info(16, 1, 1, 5, 6, 5, 0, 0, 0, 0, FormatID::R5G6B5_UNORM); + return info; + } + case D3DFMT_X8R8G8B8: + { + static const D3DFormat info(32, 1, 1, 8, 8, 8, 0, 0, 0, 0, FormatID::B8G8R8X8_UNORM); + return info; + } + case D3DFMT_A8R8G8B8: + { + static const D3DFormat info(32, 1, 1, 8, 8, 8, 8, 0, 0, 0, FormatID::B8G8R8A8_UNORM); + return info; + } + + case D3DFMT_R16F: + { + static const D3DFormat info(16, 1, 1, 16, 0, 0, 0, 0, 0, 0, FormatID::R16_FLOAT); + return info; + } + case D3DFMT_G16R16F: + { + static const D3DFormat info(32, 1, 1, 16, 16, 0, 0, 0, 0, 0, FormatID::R16G16_FLOAT); + return info; + } + case D3DFMT_A16B16G16R16F: + { + static const D3DFormat info(64, 1, 1, 16, 16, 16, 16, 0, 0, 0, + FormatID::R16G16B16A16_FLOAT); + return info; + } + case D3DFMT_R32F: + { + static const D3DFormat info(32, 1, 1, 32, 0, 0, 0, 0, 0, 0, FormatID::R32_FLOAT); + return info; + } + case D3DFMT_G32R32F: + { + static const D3DFormat info(64, 1, 1, 32, 32, 0, 0, 0, 0, 0, FormatID::R32G32_FLOAT); + return info; + } + case D3DFMT_A32B32G32R32F: + { + static const D3DFormat info(128, 1, 1, 32, 32, 32, 32, 0, 0, 0, + FormatID::R32G32B32A32_FLOAT); + return info; + } + + case D3DFMT_D16: + { + static const D3DFormat info(16, 1, 1, 0, 0, 0, 0, 0, 16, 0, FormatID::D16_UNORM); + return info; + } + case D3DFMT_D24S8: + { + static const D3DFormat info(32, 1, 1, 0, 0, 0, 0, 0, 24, 8, + FormatID::D24_UNORM_S8_UINT); + return info; + } + case D3DFMT_D24X8: + { + static const D3DFormat info(32, 1, 1, 0, 0, 0, 0, 0, 24, 0, FormatID::D16_UNORM); + return info; + } + case D3DFMT_D32: + { + static const D3DFormat info(32, 1, 1, 0, 0, 0, 0, 0, 32, 0, FormatID::D32_UNORM); + return info; + } + + case D3DFMT_DXT1: + { + static const D3DFormat info(64, 4, 4, 0, 0, 0, 0, 0, 0, 0, + FormatID::BC1_RGBA_UNORM_BLOCK); + return info; + } + case D3DFMT_DXT3: + { + static const D3DFormat info(128, 4, 4, 0, 0, 0, 0, 0, 0, 0, + FormatID::BC2_RGBA_UNORM_BLOCK); + return info; + } + case D3DFMT_DXT5: + { + static const D3DFormat info(128, 4, 4, 0, 0, 0, 0, 0, 0, 0, + FormatID::BC3_RGBA_UNORM_BLOCK); + return info; + } + + default: + { + static const D3DFormat defaultInfo; + return defaultInfo; + } + } +} + +typedef std::pair<GLint, InitializeTextureDataFunction> InternalFormatInitialzerPair; +typedef std::map<GLint, InitializeTextureDataFunction> InternalFormatInitialzerMap; + +static InternalFormatInitialzerMap BuildInternalFormatInitialzerMap() +{ + using namespace angle; // For image initialization functions + + InternalFormatInitialzerMap map; + + map.insert(InternalFormatInitialzerPair( + GL_RGB16F, Initialize4ComponentData<GLhalf, 0x0000, 0x0000, 0x0000, gl::Float16One>)); + map.insert(InternalFormatInitialzerPair( + GL_RGB32F, + Initialize4ComponentData<GLfloat, 0x00000000, 0x00000000, 0x00000000, gl::Float32One>)); + + return map; +} + +static void UnreachableLoad(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + UNREACHABLE(); +} + +typedef std::pair<GLenum, TextureFormat> D3D9FormatPair; +typedef std::map<GLenum, TextureFormat> D3D9FormatMap; + +TextureFormat::TextureFormat() + : texFormat(D3DFMT_UNKNOWN), + renderFormat(D3DFMT_UNKNOWN), + dataInitializerFunction(nullptr), + 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 : nullptr; + + info.loadFunction = loadFunction; + + map->insert(std::make_pair(internalFormat, info)); +} + +static D3D9FormatMap BuildD3D9FormatMap() +{ + using namespace angle; // For image loading functions + + D3D9FormatMap map; + + // clang-format off + // | Internal format | Texture format | Render format | Load function | + InsertD3D9FormatInfo(&map, GL_NONE, D3DFMT_NULL, D3DFMT_NULL, UnreachableLoad ); + + // We choose to downsample the GL_DEPTH_COMPONENT32_OES format to a 24-bit format because D3DFMT_D32 is not widely + // supported. We're allowed to do this because: + // - The ES spec 2.0.25 sec 3.7.1 states that we're allowed to store texture formats with internal format + // resolutions of our own choosing. + // - OES_depth_texture states that downsampling of the depth formats is allowed. + // - ANGLE_depth_texture does not state minimum required resolutions of the depth texture formats it + // introduces. + // In ES3 however, there are minimum resolutions for the texture formats and this would not be allowed. + + InsertD3D9FormatInfo(&map, GL_DEPTH_COMPONENT16, D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad ); + InsertD3D9FormatInfo(&map, GL_DEPTH_COMPONENT32_OES, D3DFMT_INTZ, D3DFMT_D24X8, UnreachableLoad ); + InsertD3D9FormatInfo(&map, GL_DEPTH24_STENCIL8_OES, D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad ); + InsertD3D9FormatInfo(&map, GL_STENCIL_INDEX8, D3DFMT_UNKNOWN, D3DFMT_D24S8, UnreachableLoad ); // TODO: What's the texture format? + + InsertD3D9FormatInfo(&map, GL_RGBA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative<GLfloat, 4> ); + InsertD3D9FormatInfo(&map, GL_RGB32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative3To4<GLfloat, gl::Float32One>); + InsertD3D9FormatInfo(&map, GL_RG32F_EXT, D3DFMT_G32R32F, D3DFMT_G32R32F, LoadToNative<GLfloat, 2> ); + InsertD3D9FormatInfo(&map, GL_R32F_EXT, D3DFMT_R32F, D3DFMT_R32F, LoadToNative<GLfloat, 1> ); + InsertD3D9FormatInfo(&map, GL_ALPHA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadA32FToRGBA32F ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadL32FToRGBA32F ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadLA32FToRGBA32F ); + + InsertD3D9FormatInfo(&map, GL_RGBA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative<GLhalf, 4> ); + InsertD3D9FormatInfo(&map, GL_RGB16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative3To4<GLhalf, gl::Float16One> ); + InsertD3D9FormatInfo(&map, GL_RG16F_EXT, D3DFMT_G16R16F, D3DFMT_G16R16F, LoadToNative<GLhalf, 2> ); + InsertD3D9FormatInfo(&map, GL_R16F_EXT, D3DFMT_R16F, D3DFMT_R16F, LoadToNative<GLhalf, 1> ); + InsertD3D9FormatInfo(&map, GL_ALPHA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadA16FToRGBA16F ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadL16FToRGBA16F ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadLA16FToRGBA16F ); + + InsertD3D9FormatInfo(&map, GL_ALPHA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadA8ToBGRA8 ); + + InsertD3D9FormatInfo(&map, GL_RGB8_OES, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRGB8ToBGRX8 ); + InsertD3D9FormatInfo(&map, GL_RGB565, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR5G6B5ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_RGBA8_OES, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGBA8ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_RGBA4, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGBA4ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_RGB5_A1, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGB5A1ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_R8_EXT, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR8ToBGRX8 ); + InsertD3D9FormatInfo(&map, GL_RG8_EXT, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRG8ToBGRX8 ); + + InsertD3D9FormatInfo(&map, GL_BGRA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadToNative<GLubyte, 4> ); + InsertD3D9FormatInfo(&map, GL_BGRA4_ANGLEX, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGRA4ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_BGR5_A1_ANGLEX, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGR5A1ToBGRA8 ); + + InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 1, 8> ); + InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 1, 8> ); + InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, D3DFMT_DXT3, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 1, 16> ); + InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, D3DFMT_DXT5, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 1, 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> ); + // clang-format on + + return map; +} + +const TextureFormat &GetTextureFormatInfo(GLenum internalFormat) +{ + static const D3D9FormatMap formatMap = BuildD3D9FormatMap(); + D3D9FormatMap::const_iterator iter = formatMap.find(internalFormat); + if (iter != formatMap.end()) + { + return iter->second; + } + else + { + static const TextureFormat defaultInfo; + return defaultInfo; + } +} + +static GLenum GetDeclTypeComponentType(D3DDECLTYPE declType) +{ + switch (declType) + { + case D3DDECLTYPE_FLOAT1: + return GL_FLOAT; + case D3DDECLTYPE_FLOAT2: + return GL_FLOAT; + case D3DDECLTYPE_FLOAT3: + return GL_FLOAT; + case D3DDECLTYPE_FLOAT4: + return GL_FLOAT; + case D3DDECLTYPE_UBYTE4: + return GL_UNSIGNED_INT; + case D3DDECLTYPE_SHORT2: + return GL_INT; + case D3DDECLTYPE_SHORT4: + return GL_INT; + case D3DDECLTYPE_UBYTE4N: + return GL_UNSIGNED_NORMALIZED; + case D3DDECLTYPE_SHORT4N: + return GL_SIGNED_NORMALIZED; + case D3DDECLTYPE_USHORT4N: + return GL_UNSIGNED_NORMALIZED; + case D3DDECLTYPE_SHORT2N: + return GL_SIGNED_NORMALIZED; + case D3DDECLTYPE_USHORT2N: + return GL_UNSIGNED_NORMALIZED; + default: + UNREACHABLE(); + return GL_NONE; + } +} + +// Attribute format conversion +enum +{ + NUM_GL_VERTEX_ATTRIB_TYPES = 6 +}; + +struct TranslationDescription +{ + DWORD capsFlag; + VertexFormat preferredConversion; + VertexFormat fallbackConversion; +}; + +// Mapping from OpenGL-ES vertex attrib type to D3D decl type: +// +// BYTE SHORT (Cast) +// BYTE-norm FLOAT (Normalize) (can't be exactly represented as SHORT-norm) +// UNSIGNED_BYTE UBYTE4 (Identity) or SHORT (Cast) +// UNSIGNED_BYTE-norm UBYTE4N (Identity) or FLOAT (Normalize) +// SHORT SHORT (Identity) +// SHORT-norm SHORT-norm (Identity) or FLOAT (Normalize) +// UNSIGNED_SHORT FLOAT (Cast) +// UNSIGNED_SHORT-norm USHORT-norm (Identity) or FLOAT (Normalize) +// FIXED (not in WebGL) FLOAT (FixedToFloat) +// FLOAT FLOAT (Identity) + +// GLToCType maps from GL type (as GLenum) to the C typedef. +template <GLenum GLType> +struct GLToCType +{}; + +template <> +struct GLToCType<GL_BYTE> +{ + typedef GLbyte type; +}; +template <> +struct GLToCType<GL_UNSIGNED_BYTE> +{ + typedef GLubyte type; +}; +template <> +struct GLToCType<GL_SHORT> +{ + typedef GLshort type; +}; +template <> +struct GLToCType<GL_UNSIGNED_SHORT> +{ + typedef GLushort type; +}; +template <> +struct GLToCType<GL_FIXED> +{ + typedef GLuint type; +}; +template <> +struct GLToCType<GL_FLOAT> +{ + typedef GLfloat type; +}; + +// This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.) +enum D3DVertexType +{ + D3DVT_FLOAT, + D3DVT_SHORT, + D3DVT_SHORT_NORM, + D3DVT_UBYTE, + D3DVT_UBYTE_NORM, + D3DVT_USHORT_NORM +}; + +// D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type. +template <unsigned int D3DType> +struct D3DToCType +{}; + +template <> +struct D3DToCType<D3DVT_FLOAT> +{ + typedef float type; +}; +template <> +struct D3DToCType<D3DVT_SHORT> +{ + typedef short type; +}; +template <> +struct D3DToCType<D3DVT_SHORT_NORM> +{ + typedef short type; +}; +template <> +struct D3DToCType<D3DVT_UBYTE> +{ + typedef unsigned char type; +}; +template <> +struct D3DToCType<D3DVT_UBYTE_NORM> +{ + typedef unsigned char type; +}; +template <> +struct D3DToCType<D3DVT_USHORT_NORM> +{ + typedef unsigned short type; +}; + +// Encode the type/size combinations that D3D permits. For each type/size it expands to a widener +// that will provide the appropriate final size. +template <unsigned int type, int size> +struct WidenRule +{}; + +template <int size> +struct WidenRule<D3DVT_FLOAT, size> : NoWiden<size> +{}; +template <int size> +struct WidenRule<D3DVT_SHORT, size> : WidenToEven<size> +{}; +template <int size> +struct WidenRule<D3DVT_SHORT_NORM, size> : WidenToEven<size> +{}; +template <int size> +struct WidenRule<D3DVT_UBYTE, size> : WidenToFour<size> +{}; +template <int size> +struct WidenRule<D3DVT_UBYTE_NORM, size> : WidenToFour<size> +{}; +template <int size> +struct WidenRule<D3DVT_USHORT_NORM, size> : WidenToEven<size> +{}; + +// VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D +// vertex type & size combination. +template <unsigned int d3dtype, int size> +struct VertexTypeFlags +{}; + +template <unsigned int _capflag, unsigned int _declflag> +struct VertexTypeFlagsHelper +{ + enum + { + capflag = _capflag + }; + enum + { + declflag = _declflag + }; +}; + +template <> +struct VertexTypeFlags<D3DVT_FLOAT, 1> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> +{}; +template <> +struct VertexTypeFlags<D3DVT_FLOAT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> +{}; +template <> +struct VertexTypeFlags<D3DVT_FLOAT, 3> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> +{}; +template <> +struct VertexTypeFlags<D3DVT_FLOAT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> +{}; +template <> +struct VertexTypeFlags<D3DVT_SHORT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> +{}; +template <> +struct VertexTypeFlags<D3DVT_SHORT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> +{}; +template <> +struct VertexTypeFlags<D3DVT_SHORT_NORM, 2> + : VertexTypeFlagsHelper<D3DDTCAPS_SHORT2N, D3DDECLTYPE_SHORT2N> +{}; +template <> +struct VertexTypeFlags<D3DVT_SHORT_NORM, 4> + : VertexTypeFlagsHelper<D3DDTCAPS_SHORT4N, D3DDECLTYPE_SHORT4N> +{}; +template <> +struct VertexTypeFlags<D3DVT_UBYTE, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4, D3DDECLTYPE_UBYTE4> +{}; +template <> +struct VertexTypeFlags<D3DVT_UBYTE_NORM, 4> + : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4N, D3DDECLTYPE_UBYTE4N> +{}; +template <> +struct VertexTypeFlags<D3DVT_USHORT_NORM, 2> + : VertexTypeFlagsHelper<D3DDTCAPS_USHORT2N, D3DDECLTYPE_USHORT2N> +{}; +template <> +struct VertexTypeFlags<D3DVT_USHORT_NORM, 4> + : VertexTypeFlagsHelper<D3DDTCAPS_USHORT4N, D3DDECLTYPE_USHORT4N> +{}; + +// VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as +// D3DVertexType enums). +template <GLenum GLtype, bool normalized> +struct VertexTypeMapping +{}; + +template <D3DVertexType Preferred, D3DVertexType Fallback = Preferred> +struct VertexTypeMappingBase +{ + enum + { + preferred = Preferred + }; + enum + { + fallback = Fallback + }; +}; + +template <> +struct VertexTypeMapping<GL_BYTE, false> : VertexTypeMappingBase<D3DVT_SHORT> +{}; // Cast +template <> +struct VertexTypeMapping<GL_BYTE, true> : VertexTypeMappingBase<D3DVT_FLOAT> +{}; // Normalize +template <> +struct VertexTypeMapping<GL_UNSIGNED_BYTE, false> : VertexTypeMappingBase<D3DVT_UBYTE, D3DVT_FLOAT> +{}; // Identity, Cast +template <> +struct VertexTypeMapping<GL_UNSIGNED_BYTE, true> + : VertexTypeMappingBase<D3DVT_UBYTE_NORM, D3DVT_FLOAT> +{}; // Identity, Normalize +template <> +struct VertexTypeMapping<GL_SHORT, false> : VertexTypeMappingBase<D3DVT_SHORT> +{}; // Identity +template <> +struct VertexTypeMapping<GL_SHORT, true> : VertexTypeMappingBase<D3DVT_SHORT_NORM, D3DVT_FLOAT> +{}; // Cast, Normalize +template <> +struct VertexTypeMapping<GL_UNSIGNED_SHORT, false> : VertexTypeMappingBase<D3DVT_FLOAT> +{}; // Cast +template <> +struct VertexTypeMapping<GL_UNSIGNED_SHORT, true> + : VertexTypeMappingBase<D3DVT_USHORT_NORM, D3DVT_FLOAT> +{}; // Cast, Normalize +template <bool normalized> +struct VertexTypeMapping<GL_FIXED, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> +{}; // FixedToFloat +template <bool normalized> +struct VertexTypeMapping<GL_FLOAT, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> +{}; // Identity + +// Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule +// (Cast, Normalize, Identity, FixedToFloat). The conversion rules themselves are defined in +// vertexconversion.h. + +// Almost all cases are covered by Cast (including those that are actually Identity since Cast<T,T> +// knows it's an identity mapping). +template <GLenum fromType, bool normalized, unsigned int toType> +struct ConversionRule : Cast<typename GLToCType<fromType>::type, typename D3DToCType<toType>::type> +{}; + +// All conversions from normalized types to float use the Normalize operator. +template <GLenum fromType> +struct ConversionRule<fromType, true, D3DVT_FLOAT> : Normalize<typename GLToCType<fromType>::type> +{}; + +// Use a full specialization for this so that it preferentially matches ahead of the generic +// normalize-to-float rules. +template <> +struct ConversionRule<GL_FIXED, true, D3DVT_FLOAT> : FixedToFloat<GLint, 16> +{}; +template <> +struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : FixedToFloat<GLint, 16> +{}; + +// A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues +// (i.e. 0/1) whether it is normalized or not. +template <class T, bool normalized> +struct DefaultVertexValuesStage2 +{}; + +template <class T> +struct DefaultVertexValuesStage2<T, true> : NormalizedDefaultValues<T> +{}; +template <class T> +struct DefaultVertexValuesStage2<T, false> : SimpleDefaultValues<T> +{}; + +// Work out the default value rule for a D3D type (expressed as the C type) and +template <class T, bool normalized> +struct DefaultVertexValues : DefaultVertexValuesStage2<T, normalized> +{}; +template <bool normalized> +struct DefaultVertexValues<float, normalized> : SimpleDefaultValues<float> +{}; + +// Policy rules for use with Converter, to choose whether to use the preferred or fallback +// conversion. The fallback conversion produces an output that all D3D9 devices must support. +template <class T> +struct UsePreferred +{ + enum + { + type = T::preferred + }; +}; +template <class T> +struct UseFallback +{ + enum + { + type = T::fallback + }; +}; + +// Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback +// conversion, it provides all the members of the appropriate VertexDataConverter, the +// D3DCAPS9::DeclTypes flag in cap flag and the D3DDECLTYPE member needed for the vertex declaration +// in declflag. +template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule> +struct Converter + : VertexDataConverter< + typename GLToCType<fromType>::type, + WidenRule<PreferenceRule<VertexTypeMapping<fromType, normalized>>::type, size>, + ConversionRule<fromType, + normalized, + PreferenceRule<VertexTypeMapping<fromType, normalized>>::type>, + DefaultVertexValues<typename D3DToCType<PreferenceRule< + VertexTypeMapping<fromType, normalized>>::type>::type, + normalized>> +{ + private: + enum + { + d3dtype = PreferenceRule<VertexTypeMapping<fromType, normalized>>::type + }; + enum + { + d3dsize = WidenRule<d3dtype, size>::finalWidth + }; + + public: + enum + { + capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag + }; + enum + { + declflag = VertexTypeFlags<d3dtype, d3dsize>::declflag + }; +}; + +VertexFormat::VertexFormat() + : conversionType(VERTEX_CONVERT_NONE), + outputElementSize(0), + copyFunction(nullptr), + 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, angle::FormatID vertexFormatID) +{ + static bool initialized = false; + static DWORD initializedDeclTypes = 0; + static VertexFormat formatConverters[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; + if (initializedDeclTypes != supportedDeclTypes) + { + const TranslationDescription + translations[NUM_GL_VERTEX_ATTRIB_TYPES][2] + [4] = // [GL types as enumerated by typeIndex()][normalized][size-1] + {TRANSLATIONS_FOR_TYPE(GL_BYTE), TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE), + TRANSLATIONS_FOR_TYPE(GL_SHORT), TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT), + TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FIXED), TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FLOAT)}; + for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++) + { + for (unsigned int j = 0; j < 2; j++) + { + for (unsigned int k = 0; k < 4; k++) + { + if (translations[i][j][k].capsFlag == 0 || + (supportedDeclTypes & translations[i][j][k].capsFlag) != 0) + { + formatConverters[i][j][k] = translations[i][j][k].preferredConversion; + } + else + { + formatConverters[i][j][k] = translations[i][j][k].fallbackConversion; + } + } + } + } + initialized = true; + initializedDeclTypes = supportedDeclTypes; + } + + const gl::VertexFormat &vertexFormat = gl::GetVertexFormatFromID(vertexFormatID); + + // Pure integer attributes only supported in ES3.0 + ASSERT(!vertexFormat.pureInteger); + return formatConverters[ComputeTypeIndex(vertexFormat.type)][vertexFormat.normalized] + [vertexFormat.components - 1]; +} +} // namespace d3d9 +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/formatutils9.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/formatutils9.h new file mode 100644 index 0000000000..ba1a1ca981 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/formatutils9.h @@ -0,0 +1,93 @@ +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils9.h: Queries for GL image formats and their translations to D3D9 +// formats. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_FORMATUTILS9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_FORMATUTILS9_H_ + +#include <map> + +#include "common/platform.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/Format.h" +#include "libANGLE/renderer/copyvertex.h" +#include "libANGLE/renderer/d3d/formatutilsD3D.h" +#include "libANGLE/renderer/renderer_utils.h" + +namespace rx +{ + +class Renderer9; + +namespace d3d9 +{ + +struct D3DFormat +{ + D3DFormat(); + D3DFormat(GLuint pixelBytes, + GLuint blockWidth, + GLuint blockHeight, + GLuint redBits, + GLuint greenBits, + GLuint blueBits, + GLuint alphaBits, + GLuint luminanceBits, + GLuint depthBits, + GLuint stencilBits, + angle::FormatID formatID); + + const angle::Format &info() const { return angle::Format::Get(formatID); } + + GLuint pixelBytes; + GLuint blockWidth; + GLuint blockHeight; + + GLuint redBits; + GLuint greenBits; + GLuint blueBits; + GLuint alphaBits; + GLuint luminanceBits; + + GLuint depthBits; + GLuint stencilBits; + + angle::FormatID formatID; +}; + +const D3DFormat &GetD3DFormatInfo(D3DFORMAT format); + +struct VertexFormat +{ + VertexFormat(); + + VertexConversionType conversionType; + size_t outputElementSize; + VertexCopyFunction copyFunction; + D3DDECLTYPE nativeFormat; + GLenum componentType; +}; +const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, angle::FormatID vertexFormatID); + +struct TextureFormat +{ + TextureFormat(); + + D3DFORMAT texFormat; + D3DFORMAT renderFormat; + + InitializeTextureDataFunction dataInitializerFunction; + + LoadImageFunction loadFunction; +}; +const TextureFormat &GetTextureFormatInfo(GLenum internalFormat); +} // namespace d3d9 +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_FORMATUTILS9_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp new file mode 100644 index 0000000000..8c56837299 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp @@ -0,0 +1,826 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// renderer9_utils.cpp: Conversion functions and other utility routines +// specific to the D3D9 renderer. + +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" + +#include "common/debug.h" +#include "common/mathutil.h" + +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/driver_utils.h" +#include "platform/FeaturesD3D.h" +#include "platform/Platform.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_CLAMP_TO_BORDER: + d3dWrap = D3DTADDRESS_BORDER; + break; + case GL_MIRRORED_REPEAT: + d3dWrap = D3DTADDRESS_MIRROR; + break; + default: + UNREACHABLE(); + } + + return d3dWrap; +} + +D3DCULL ConvertCullMode(gl::CullFaceMode cullFace, GLenum frontFace) +{ + D3DCULL cull = D3DCULL_CCW; + switch (cullFace) + { + case gl::CullFaceMode::Front: + cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW); + break; + case gl::CullFaceMode::Back: + cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW); + break; + case gl::CullFaceMode::FrontAndBack: + cull = D3DCULL_NONE; // culling will be handled during draw + break; + default: + UNREACHABLE(); + } + + return cull; +} + +D3DCUBEMAP_FACES ConvertCubeFace(gl::TextureTarget cubeFace) +{ + D3DCUBEMAP_FACES face = D3DCUBEMAP_FACE_POSITIVE_X; + + switch (cubeFace) + { + case gl::TextureTarget::CubeMapPositiveX: + face = D3DCUBEMAP_FACE_POSITIVE_X; + break; + case gl::TextureTarget::CubeMapNegativeX: + face = D3DCUBEMAP_FACE_NEGATIVE_X; + break; + case gl::TextureTarget::CubeMapPositiveY: + face = D3DCUBEMAP_FACE_POSITIVE_Y; + break; + case gl::TextureTarget::CubeMapNegativeY: + face = D3DCUBEMAP_FACE_NEGATIVE_Y; + break; + case gl::TextureTarget::CubeMapPositiveZ: + face = D3DCUBEMAP_FACE_POSITIVE_Z; + break; + case gl::TextureTarget::CubeMapNegativeZ: + face = D3DCUBEMAP_FACE_NEGATIVE_Z; + break; + default: + UNREACHABLE(); + } + + return face; +} + +DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha) +{ + return (red ? D3DCOLORWRITEENABLE_RED : 0) | (green ? D3DCOLORWRITEENABLE_GREEN : 0) | + (blue ? D3DCOLORWRITEENABLE_BLUE : 0) | (alpha ? D3DCOLORWRITEENABLE_ALPHA : 0); +} + +D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy) +{ + if (maxAnisotropy > 1.0f) + { + return D3DTEXF_ANISOTROPIC; + } + + D3DTEXTUREFILTERTYPE d3dMagFilter = D3DTEXF_POINT; + switch (magFilter) + { + case GL_NEAREST: + d3dMagFilter = D3DTEXF_POINT; + break; + case GL_LINEAR: + d3dMagFilter = D3DTEXF_LINEAR; + break; + default: + UNREACHABLE(); + } + + return d3dMagFilter; +} + +void ConvertMinFilter(GLenum minFilter, + D3DTEXTUREFILTERTYPE *d3dMinFilter, + D3DTEXTUREFILTERTYPE *d3dMipFilter, + float *d3dLodBias, + float maxAnisotropy, + size_t baseLevel) +{ + switch (minFilter) + { + case GL_NEAREST: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_NONE; + break; + case GL_LINEAR: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_NONE; + break; + case GL_NEAREST_MIPMAP_NEAREST: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_POINT; + break; + case GL_LINEAR_MIPMAP_NEAREST: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_POINT; + break; + case GL_NEAREST_MIPMAP_LINEAR: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_LINEAR; + break; + case GL_LINEAR_MIPMAP_LINEAR: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_LINEAR; + break; + default: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_NONE; + UNREACHABLE(); + } + + // Disabling mipmapping will always sample from level 0 of the texture. It is possible to work + // around this by modifying D3DSAMP_MAXMIPLEVEL to force a specific mip level to become the + // lowest sampled mip level and using a large negative value for D3DSAMP_MIPMAPLODBIAS to + // ensure that only the base mip level is sampled. + if (baseLevel > 0 && *d3dMipFilter == D3DTEXF_NONE) + { + *d3dMipFilter = D3DTEXF_POINT; + *d3dLodBias = -static_cast<float>(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + } + else + { + *d3dLodBias = 0.0f; + } + + if (maxAnisotropy > 1.0f) + { + *d3dMinFilter = D3DTEXF_ANISOTROPIC; + } +} + +D3DQUERYTYPE ConvertQueryType(gl::QueryType type) +{ + switch (type) + { + case gl::QueryType::AnySamples: + case gl::QueryType::AnySamplesConservative: + return D3DQUERYTYPE_OCCLUSION; + case gl::QueryType::CommandsCompleted: + return D3DQUERYTYPE_EVENT; + default: + UNREACHABLE(); + return static_cast<D3DQUERYTYPE>(0); + } +} + +D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples) +{ + return (samples > 1) ? static_cast<D3DMULTISAMPLE_TYPE>(samples) : D3DMULTISAMPLE_NONE; +} + +} // namespace gl_d3d9 + +namespace d3d9_gl +{ + +unsigned int GetReservedVaryingVectors() +{ + // We reserve two registers for "dx_Position" and "gl_Position". The spec says they + // don't count towards the varying limit, so we must make space for them. We also + // reserve the last register since it can only pass a PSIZE, and not any arbitrary + // varying. + return 3; +} + +unsigned int GetReservedVertexUniformVectors() +{ + return 3; // dx_ViewCoords, dx_ViewAdjust and dx_DepthRange. +} + +unsigned int GetReservedFragmentUniformVectors() +{ + return 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange. +} + +GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type) +{ + return (type != D3DMULTISAMPLE_NONMASKABLE) ? type : 0; +} + +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format) +{ + GLenum internalFormat = d3d9::GetD3DFormatInfo(d3dformat).info().glInternalFormat; + GLenum convertedFormat = gl::GetSizedInternalFormatInfo(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::GetSizedInternalFormatInfo(internalFormat); + + if (d3dFormatInfo.texFormat != D3DFMT_UNKNOWN) + { + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat( + adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)); + } + else + { + textureCaps.texturable = + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, + D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)) && + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, + D3DRTYPE_CUBETEXTURE, d3dFormatInfo.texFormat)); + } + + textureCaps.filterable = SUCCEEDED( + d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_FILTER, + D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)); + } + + if (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN) + { + textureCaps.textureAttachment = SUCCEEDED( + d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_RENDERTARGET, + D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat)); + + if ((formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) && + !textureCaps.textureAttachment) + { + textureCaps.textureAttachment = SUCCEEDED( + d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_DEPTHSTENCIL, + D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat)); + } + textureCaps.renderbuffer = textureCaps.textureAttachment; + + textureCaps.sampleCounts.insert(1); + for (unsigned int i = D3DMULTISAMPLE_2_SAMPLES; i <= D3DMULTISAMPLE_16_SAMPLES; i++) + { + D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_TYPE(i); + + HRESULT result = d3d9->CheckDeviceMultiSampleType( + adapter, deviceType, d3dFormatInfo.renderFormat, TRUE, multisampleType, nullptr); + if (SUCCEEDED(result)) + { + textureCaps.sampleCounts.insert(i); + } + } + } + + return textureCaps; +} + +void GenerateCaps(IDirect3D9 *d3d9, + IDirect3DDevice9 *device, + D3DDEVTYPE deviceType, + UINT adapter, + gl::Caps *caps, + gl::TextureCapsMap *textureCapsMap, + gl::Extensions *extensions, + gl::Limitations *limitations) +{ + D3DCAPS9 deviceCaps; + if (FAILED(d3d9->GetDeviceCaps(adapter, deviceType, &deviceCaps))) + { + // Can't continue with out device caps + return; + } + + D3DDISPLAYMODE currentDisplayMode; + d3d9->GetAdapterDisplayMode(adapter, ¤tDisplayMode); + + GLuint maxSamples = 0; + for (GLenum internalFormat : gl::GetAllSizedInternalFormats()) + { + gl::TextureCaps textureCaps = GenerateTextureFormatCaps(internalFormat, d3d9, deviceType, + adapter, currentDisplayMode.Format); + textureCapsMap->insert(internalFormat, textureCaps); + + maxSamples = std::max(maxSamples, textureCaps.getMaxSamples()); + + if (gl::GetSizedInternalFormatInfo(internalFormat).compressed) + { + caps->compressedTextureFormats.push_back(internalFormat); + } + } + + // GL core feature limits + caps->maxElementIndex = static_cast<GLint64>(std::numeric_limits<unsigned int>::max()); + + // 3D textures are unimplemented in D3D9 + caps->max3DTextureSize = 1; + + // Only one limit in GL, use the minimum dimension + caps->max2DTextureSize = std::min(deviceCaps.MaxTextureWidth, deviceCaps.MaxTextureHeight); + + // D3D treats cube maps as a special case of 2D textures + caps->maxCubeMapTextureSize = caps->max2DTextureSize; + + // Array textures are not available in D3D9 + caps->maxArrayTextureLayers = 1; + + // ES3-only feature + caps->maxLODBias = 0.0f; + + // No specific limits on render target size, maximum 2D texture size is equivalent + caps->maxRenderbufferSize = caps->max2DTextureSize; + + // Draw buffers are not supported in D3D9 + caps->maxDrawBuffers = 1; + caps->maxColorAttachments = 1; + + // No specific limits on viewport size, maximum 2D texture size is equivalent + caps->maxViewportWidth = caps->max2DTextureSize; + caps->maxViewportHeight = caps->maxViewportWidth; + + // Point size is clamped to 1.0f when the shader model is less than 3 + caps->minAliasedPointSize = 1.0f; + caps->maxAliasedPointSize = + ((D3DSHADER_VERSION_MAJOR(deviceCaps.PixelShaderVersion) >= 3) ? deviceCaps.MaxPointSize + : 1.0f); + + // Wide lines not supported + caps->minAliasedLineWidth = 1.0f; + caps->maxAliasedLineWidth = 1.0f; + + // Primitive count limits (unused in ES2) + caps->maxElementsIndices = 0; + caps->maxElementsVertices = 0; + + // Program and shader binary formats (no supported shader binary formats) + caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE); + + caps->vertexHighpFloat.setIEEEFloat(); + caps->vertexMediumpFloat.setIEEEFloat(); + caps->vertexLowpFloat.setIEEEFloat(); + caps->fragmentHighpFloat.setIEEEFloat(); + caps->fragmentMediumpFloat.setIEEEFloat(); + caps->fragmentLowpFloat.setIEEEFloat(); + + // Some (most) hardware only supports single-precision floating-point numbers, + // which can accurately represent integers up to +/-16777216 + caps->vertexHighpInt.setSimulatedInt(24); + caps->vertexMediumpInt.setSimulatedInt(24); + caps->vertexLowpInt.setSimulatedInt(24); + caps->fragmentHighpInt.setSimulatedInt(24); + caps->fragmentMediumpInt.setSimulatedInt(24); + caps->fragmentLowpInt.setSimulatedInt(24); + + // WaitSync is ES3-only, set to zero + caps->maxServerWaitTimeout = 0; + + // Vertex shader limits + caps->maxVertexAttributes = 16; + // Vertex Attrib Binding not supported. + caps->maxVertexAttribBindings = caps->maxVertexAttributes; + + const size_t MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256; + caps->maxVertexUniformVectors = + MAX_VERTEX_CONSTANT_VECTORS_D3D9 - GetReservedVertexUniformVectors(); + caps->maxShaderUniformComponents[gl::ShaderType::Vertex] = caps->maxVertexUniformVectors * 4; + + caps->maxShaderUniformBlocks[gl::ShaderType::Vertex] = 0; + + // SM3 only supports 12 output variables, but the special 12th register is only for PSIZE. + const unsigned int MAX_VERTEX_OUTPUT_VECTORS_SM3 = 12 - GetReservedVaryingVectors(); + const unsigned int MAX_VERTEX_OUTPUT_VECTORS_SM2 = 10 - GetReservedVaryingVectors(); + 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->maxShaderTextureImageUnits[gl::ShaderType::Vertex] = MAX_TEXTURE_IMAGE_UNITS_VTF_SM3; + } + else + { + caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] = 0; + } + + // Fragment shader limits + const size_t MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224; + const size_t MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32; + caps->maxFragmentUniformVectors = + ((deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) ? MAX_PIXEL_CONSTANT_VECTORS_SM3 + : MAX_PIXEL_CONSTANT_VECTORS_SM2) - + GetReservedFragmentUniformVectors(); + caps->maxShaderUniformComponents[gl::ShaderType::Fragment] = + caps->maxFragmentUniformVectors * 4; + caps->maxShaderUniformBlocks[gl::ShaderType::Fragment] = 0; + caps->maxFragmentInputComponents = caps->maxVertexOutputComponents; + caps->maxShaderTextureImageUnits[gl::ShaderType::Fragment] = 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->maxCombinedShaderUniformComponents[gl::ShaderType::Vertex] = 0; + caps->maxCombinedShaderUniformComponents[gl::ShaderType::Fragment] = 0; + caps->maxVaryingComponents = 0; + + // Aggregate shader limits + caps->maxVaryingVectors = caps->maxVertexOutputComponents / 4; + caps->maxCombinedTextureImageUnits = caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] + + caps->maxShaderTextureImageUnits[gl::ShaderType::Fragment]; + + // Transform feedback limits + caps->maxTransformFeedbackInterleavedComponents = 0; + caps->maxTransformFeedbackSeparateAttributes = 0; + caps->maxTransformFeedbackSeparateComponents = 0; + + // Multisample limits + caps->maxSamples = maxSamples; + + // GL extension support + extensions->setTextureExtensionSupport(*textureCapsMap); + extensions->elementIndexUint = deviceCaps.MaxVertexIndex >= (1 << 16); + extensions->getProgramBinary = true; + extensions->rgb8rgba8 = true; + extensions->readFormatBGRA = true; + extensions->pixelBufferObject = false; + extensions->mapBuffer = false; + extensions->mapBufferRange = false; + + // D3D does not allow depth textures to have more than one mipmap level OES_depth_texture + // allows for that so we can't implement full support with the D3D9 back end. + extensions->depthTextureOES = false; + + // textureRG is emulated and not performant. + extensions->textureRG = false; + + D3DADAPTER_IDENTIFIER9 adapterId = {}; + if (SUCCEEDED(d3d9->GetAdapterIdentifier(adapter, 0, &adapterId))) + { + // ATI cards on XP have problems with non-power-of-two textures. + extensions->textureNPOT = !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) && + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && + !(!isWindowsVistaOrGreater() && IsAMD(adapterId.VendorId)); + + // Disable depth texture support on AMD cards (See ANGLE issue 839) + if (IsAMD(adapterId.VendorId)) + { + extensions->depthTextureANGLE = false; + extensions->depthTextureOES = false; + } + } + else + { + extensions->textureNPOT = false; + } + + extensions->drawBuffers = false; + extensions->textureStorage = true; + + // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per + // the spec + extensions->textureFilterAnisotropic = + (deviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && deviceCaps.MaxAnisotropy >= 2; + extensions->maxTextureAnisotropy = static_cast<GLfloat>(deviceCaps.MaxAnisotropy); + + // Check occlusion query support by trying to create one + IDirect3DQuery9 *occlusionQuery = nullptr; + extensions->occlusionQueryBoolean = + SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery; + SafeRelease(occlusionQuery); + + // Check event query support by trying to create one + IDirect3DQuery9 *eventQuery = nullptr; + extensions->fence = + SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery; + SafeRelease(eventQuery); + + extensions->disjointTimerQuery = false; + extensions->robustness = true; + // It seems that only DirectX 10 and higher enforce the well-defined behavior of always + // returning zero values when out-of-bounds reads. See + // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_robustness.txt + extensions->robustBufferAccessBehavior = false; + extensions->blendMinMax = true; + // Although according to + // https://docs.microsoft.com/en-us/windows/desktop/direct3ddxgi/format-support-for-direct3d-feature-level-9-1-hardware + // D3D9 doesn't have full blending capability for RGBA32F. But turns out it could provide + // correct blending result in reality. As a result of some regression reports by client app, we + // decided to turn floatBlend on for D3D9 + extensions->floatBlend = true; + extensions->framebufferBlit = true; + extensions->framebufferMultisample = true; + extensions->instancedArraysANGLE = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0); + // D3D9 requires at least one attribute that has a divisor of 0, which isn't required by the EXT + // extension + extensions->instancedArraysEXT = false; + extensions->packReverseRowOrder = true; + extensions->standardDerivatives = + (deviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0; + extensions->shaderTextureLOD = true; + extensions->fragDepth = true; + extensions->textureUsage = true; + extensions->translatedShaderSource = true; + extensions->fboRenderMipmap = false; + extensions->discardFramebuffer = false; // It would be valid to set this to true, since + // glDiscardFramebufferEXT is just a hint + extensions->colorBufferFloat = false; + extensions->debugMarker = true; + extensions->eglImage = true; + extensions->eglImageExternal = true; + extensions->unpackSubimage = true; + extensions->packSubimage = true; + extensions->syncQuery = extensions->fence; + extensions->copyTexture = true; + extensions->textureBorderClamp = true; + + // D3D9 has no concept of separate masks and refs for front and back faces in the depth stencil + // state. + limitations->noSeparateStencilRefsAndMasks = true; + + // D3D9 shader models have limited support for looping, so the Appendix A + // index/loop limitations are necessary. Workarounds that are needed to + // support dynamic indexing of vectors on HLSL also don't work on D3D9. + limitations->shadersRequireIndexedLoopValidation = true; + + // D3D9 cannot support constant color and alpha blend funcs together + limitations->noSimultaneousConstantColorAndAlphaBlendFunc = true; + + // D3D9 cannot support packing more than one variable to a single varying. + // TODO(jmadill): Implement more sophisticated component packing in D3D9. + limitations->noFlexibleVaryingPacking = true; + + // D3D9 does not support vertex attribute aliasing + limitations->noVertexAttributeAliasing = true; +} + +} // namespace d3d9_gl + +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; +} + +void InitializeFeatures(angle::FeaturesD3D *features) +{ + features->mrtPerfWorkaround.enabled = true; + features->setDataFasterThanImageUpload.enabled = false; + features->setDataFasterThanImageUploadOn128bitFormats.enabled = false; + features->useInstancedPointSpriteEmulation.enabled = false; + + // TODO(jmadill): Disable workaround when we have a fixed compiler DLL. + features->expandIntegerPowExpressions.enabled = true; + + // Never clear for robust resource init. This matches Chrome's texture clearning behaviour. + features->allowClearForRobustResourceInit.enabled = false; + + // Call platform hooks for testing overrides. + auto *platform = ANGLEPlatformCurrent(); + platform->overrideWorkaroundsD3D(platform, features); +} + +} // namespace d3d9 + +} // namespace rx diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h new file mode 100644 index 0000000000..5780837fec --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h @@ -0,0 +1,105 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// renderer9_utils.h: Conversion functions and other utility routines +// specific to the D3D9 renderer + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_ + +#include "common/Color.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Error.h" +#include "platform/FeaturesD3D.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(gl::CullFaceMode cullFace, GLenum frontFace); +D3DCUBEMAP_FACES ConvertCubeFace(gl::TextureTarget cubeFace); +DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha); +D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy); +void ConvertMinFilter(GLenum minFilter, + D3DTEXTUREFILTERTYPE *d3dMinFilter, + D3DTEXTUREFILTERTYPE *d3dMipFilter, + float *d3dLodBias, + float maxAnisotropy, + size_t baseLevel); +D3DQUERYTYPE ConvertQueryType(gl::QueryType type); + +D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples); + +} // namespace gl_d3d9 + +namespace d3d9_gl +{ + +unsigned int GetReservedVaryingVectors(); + +unsigned int GetReservedVertexUniformVectors(); + +unsigned int GetReservedFragmentUniformVectors(); + +GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type); + +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format); + +void GenerateCaps(IDirect3D9 *d3d9, + IDirect3DDevice9 *device, + D3DDEVTYPE deviceType, + UINT adapter, + gl::Caps *caps, + gl::TextureCapsMap *textureCapsMap, + gl::Extensions *extensions, + gl::Limitations *limitations); +} // namespace d3d9_gl + +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; + } +} + +void InitializeFeatures(angle::FeaturesD3D *features); +} // namespace d3d9 + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_ diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskpremultps.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskpremultps.h new file mode 100644 index 0000000000..04868aeb9c --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskpremultps.h @@ -0,0 +1,50 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// +// Parameters: +// +// float4 add; +// float4 mult; +// sampler2D tex; +// +// +// Registers: +// +// Name Reg Size +// ------------ ----- ---- +// mult c0 1 +// add c1 1 +// tex s0 1 +// + + ps_2_0 + dcl t0.xy + dcl_2d s0 + texld r0, t0, s0 + mul r0.xyz, r0.w, r0 + mov r1, c0 + mad r0, r0, r1, c1 + mov oC0, r0 + +// approximately 5 instruction slots used (1 texture, 4 arithmetic) +#endif + +const BYTE g_ps20_componentmaskpremultps[] = { + 0, 2, 255, 255, 254, 255, 50, 0, 67, 84, 65, 66, 28, 0, 0, 0, 143, 0, 0, + 0, 0, 2, 255, 255, 3, 0, 0, 0, 28, 0, 0, 0, 0, 1, 0, 0, 136, 0, + 0, 0, 88, 0, 0, 0, 2, 0, 1, 0, 1, 0, 0, 0, 92, 0, 0, 0, 0, + 0, 0, 0, 108, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 92, 0, 0, 0, + 0, 0, 0, 0, 113, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 120, 0, 0, + 0, 0, 0, 0, 0, 97, 100, 100, 0, 1, 0, 3, 0, 1, 0, 4, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 109, 117, 108, 116, 0, 116, 101, 120, 0, 171, 171, 171, 4, + 0, 12, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 112, 115, 95, 50, + 95, 48, 0, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 72, 76, + 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, + 54, 46, 51, 46, 57, 54, 48, 48, 46, 49, 54, 51, 56, 52, 0, 171, 171, 171, 31, + 0, 0, 2, 0, 0, 0, 128, 0, 0, 3, 176, 31, 0, 0, 2, 0, 0, 0, 144, + 0, 8, 15, 160, 66, 0, 0, 3, 0, 0, 15, 128, 0, 0, 228, 176, 0, 8, 228, + 160, 5, 0, 0, 3, 0, 0, 7, 128, 0, 0, 255, 128, 0, 0, 228, 128, 1, 0, + 0, 2, 1, 0, 15, 128, 0, 0, 228, 160, 4, 0, 0, 4, 0, 0, 15, 128, 0, + 0, 228, 128, 1, 0, 228, 128, 1, 0, 228, 160, 1, 0, 0, 2, 0, 8, 15, 128, + 0, 0, 228, 128, 255, 255, 0, 0}; diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h new file mode 100644 index 0000000000..06673ae5f7 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h @@ -0,0 +1,48 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// +// Parameters: +// +// float4 add; +// float4 mult; +// sampler2D tex; +// +// +// Registers: +// +// Name Reg Size +// ------------ ----- ---- +// mult c0 1 +// add c1 1 +// tex s0 1 +// + + ps_2_0 + dcl t0.xy + dcl_2d s0 + texld r0, t0, s0 + mov r1, c0 + mad r0, r0, r1, c1 + mov oC0, r0 + +// approximately 4 instruction slots used (1 texture, 3 arithmetic) +#endif + +const BYTE g_ps20_componentmaskps[] = { + 0, 2, 255, 255, 254, 255, 50, 0, 67, 84, 65, 66, 28, 0, 0, 0, 143, 0, 0, + 0, 0, 2, 255, 255, 3, 0, 0, 0, 28, 0, 0, 0, 0, 1, 0, 0, 136, 0, + 0, 0, 88, 0, 0, 0, 2, 0, 1, 0, 1, 0, 0, 0, 92, 0, 0, 0, 0, + 0, 0, 0, 108, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 92, 0, 0, 0, + 0, 0, 0, 0, 113, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 120, 0, 0, + 0, 0, 0, 0, 0, 97, 100, 100, 0, 1, 0, 3, 0, 1, 0, 4, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 109, 117, 108, 116, 0, 116, 101, 120, 0, 171, 171, 171, 4, + 0, 12, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 112, 115, 95, 50, + 95, 48, 0, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 72, 76, + 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, + 54, 46, 51, 46, 57, 54, 48, 48, 46, 49, 54, 51, 56, 52, 0, 171, 171, 171, 31, + 0, 0, 2, 0, 0, 0, 128, 0, 0, 3, 176, 31, 0, 0, 2, 0, 0, 0, 144, + 0, 8, 15, 160, 66, 0, 0, 3, 0, 0, 15, 128, 0, 0, 228, 176, 0, 8, 228, + 160, 1, 0, 0, 2, 1, 0, 15, 128, 0, 0, 228, 160, 4, 0, 0, 4, 0, 0, + 15, 128, 0, 0, 228, 128, 1, 0, 228, 128, 1, 0, 228, 160, 1, 0, 0, 2, 0, + 8, 15, 128, 0, 0, 228, 128, 255, 255, 0, 0}; diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskunmultps.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskunmultps.h new file mode 100644 index 0000000000..ad15364bb8 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskunmultps.h @@ -0,0 +1,54 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// +// Parameters: +// +// float4 add; +// float4 mult; +// sampler2D tex; +// +// +// Registers: +// +// Name Reg Size +// ------------ ----- ---- +// mult c0 1 +// add c1 1 +// tex s0 1 +// + + ps_2_0 + dcl t0.xy + dcl_2d s0 + texld r0, t0, s0 + rcp r1.w, r0.w + mul r1.xyz, r0, r1.w + cmp r0.xyz, -r0.w, r0, r1 + mov r1, c0 + mad r0, r0, r1, c1 + mov oC0, r0 + +// approximately 7 instruction slots used (1 texture, 6 arithmetic) +#endif + +const BYTE g_ps20_componentmaskunmultps[] = { + 0, 2, 255, 255, 254, 255, 50, 0, 67, 84, 65, 66, 28, 0, 0, 0, 143, 0, 0, + 0, 0, 2, 255, 255, 3, 0, 0, 0, 28, 0, 0, 0, 0, 1, 0, 0, 136, 0, + 0, 0, 88, 0, 0, 0, 2, 0, 1, 0, 1, 0, 0, 0, 92, 0, 0, 0, 0, + 0, 0, 0, 108, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 92, 0, 0, 0, + 0, 0, 0, 0, 113, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 120, 0, 0, + 0, 0, 0, 0, 0, 97, 100, 100, 0, 1, 0, 3, 0, 1, 0, 4, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 109, 117, 108, 116, 0, 116, 101, 120, 0, 171, 171, 171, 4, + 0, 12, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 112, 115, 95, 50, + 95, 48, 0, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 72, 76, + 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, + 54, 46, 51, 46, 57, 54, 48, 48, 46, 49, 54, 51, 56, 52, 0, 171, 171, 171, 31, + 0, 0, 2, 0, 0, 0, 128, 0, 0, 3, 176, 31, 0, 0, 2, 0, 0, 0, 144, + 0, 8, 15, 160, 66, 0, 0, 3, 0, 0, 15, 128, 0, 0, 228, 176, 0, 8, 228, + 160, 6, 0, 0, 2, 1, 0, 8, 128, 0, 0, 255, 128, 5, 0, 0, 3, 1, 0, + 7, 128, 0, 0, 228, 128, 1, 0, 255, 128, 88, 0, 0, 4, 0, 0, 7, 128, 0, + 0, 255, 129, 0, 0, 228, 128, 1, 0, 228, 128, 1, 0, 0, 2, 1, 0, 15, 128, + 0, 0, 228, 160, 4, 0, 0, 4, 0, 0, 15, 128, 0, 0, 228, 128, 1, 0, 228, + 128, 1, 0, 228, 160, 1, 0, 0, 2, 0, 8, 15, 128, 0, 0, 228, 128, 255, 255, + 0, 0}; diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/luminancepremultps.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/luminancepremultps.h new file mode 100644 index 0000000000..274a7824f9 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/luminancepremultps.h @@ -0,0 +1,50 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// +// Parameters: +// +// float4 add; +// float4 mult; +// sampler2D tex; +// +// +// Registers: +// +// Name Reg Size +// ------------ ----- ---- +// mult c0 1 +// add c1 1 +// tex s0 1 +// + + ps_2_0 + dcl t0.xy + dcl_2d s0 + texld r0, t0, s0 + mul r0.xyz, r0.w, r0.x + mov r1, c0 + mad r0, r0, r1, c1 + mov oC0, r0 + +// approximately 5 instruction slots used (1 texture, 4 arithmetic) +#endif + +const BYTE g_ps20_luminancepremultps[] = { + 0, 2, 255, 255, 254, 255, 50, 0, 67, 84, 65, 66, 28, 0, 0, 0, 143, 0, 0, + 0, 0, 2, 255, 255, 3, 0, 0, 0, 28, 0, 0, 0, 0, 1, 0, 0, 136, 0, + 0, 0, 88, 0, 0, 0, 2, 0, 1, 0, 1, 0, 0, 0, 92, 0, 0, 0, 0, + 0, 0, 0, 108, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 92, 0, 0, 0, + 0, 0, 0, 0, 113, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 120, 0, 0, + 0, 0, 0, 0, 0, 97, 100, 100, 0, 1, 0, 3, 0, 1, 0, 4, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 109, 117, 108, 116, 0, 116, 101, 120, 0, 171, 171, 171, 4, + 0, 12, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 112, 115, 95, 50, + 95, 48, 0, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 72, 76, + 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, + 54, 46, 51, 46, 57, 54, 48, 48, 46, 49, 54, 51, 56, 52, 0, 171, 171, 171, 31, + 0, 0, 2, 0, 0, 0, 128, 0, 0, 3, 176, 31, 0, 0, 2, 0, 0, 0, 144, + 0, 8, 15, 160, 66, 0, 0, 3, 0, 0, 15, 128, 0, 0, 228, 176, 0, 8, 228, + 160, 5, 0, 0, 3, 0, 0, 7, 128, 0, 0, 255, 128, 0, 0, 0, 128, 1, 0, + 0, 2, 1, 0, 15, 128, 0, 0, 228, 160, 4, 0, 0, 4, 0, 0, 15, 128, 0, + 0, 228, 128, 1, 0, 228, 128, 1, 0, 228, 160, 1, 0, 0, 2, 0, 8, 15, 128, + 0, 0, 228, 128, 255, 255, 0, 0}; diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceps.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceps.h new file mode 100644 index 0000000000..0be665c525 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceps.h @@ -0,0 +1,53 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// +// Parameters: +// +// float4 add; +// float4 mult; +// sampler2D tex; +// +// +// Registers: +// +// Name Reg Size +// ------------ ----- ---- +// mult c0 1 +// add c1 1 +// tex s0 1 +// + + ps_2_0 + dcl t0.xy + dcl_2d s0 + texld r0, t0, s0 + mov r1.xw, c0 + mad r0.x, r0.x, r1.x, c1.x + mad r0.y, r0.w, r1.w, c1.w + mov r1.xyz, r0.x + mov r1.w, r0.y + mov oC0, r1 + +// approximately 7 instruction slots used (1 texture, 6 arithmetic) +#endif + +const BYTE g_ps20_luminanceps[] = { + 0, 2, 255, 255, 254, 255, 50, 0, 67, 84, 65, 66, 28, 0, 0, 0, 143, 0, 0, + 0, 0, 2, 255, 255, 3, 0, 0, 0, 28, 0, 0, 0, 0, 1, 0, 0, 136, 0, + 0, 0, 88, 0, 0, 0, 2, 0, 1, 0, 1, 0, 0, 0, 92, 0, 0, 0, 0, + 0, 0, 0, 108, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 92, 0, 0, 0, + 0, 0, 0, 0, 113, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 120, 0, 0, + 0, 0, 0, 0, 0, 97, 100, 100, 0, 1, 0, 3, 0, 1, 0, 4, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 109, 117, 108, 116, 0, 116, 101, 120, 0, 171, 171, 171, 4, + 0, 12, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 112, 115, 95, 50, + 95, 48, 0, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 72, 76, + 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, + 54, 46, 51, 46, 57, 54, 48, 48, 46, 49, 54, 51, 56, 52, 0, 171, 171, 171, 31, + 0, 0, 2, 0, 0, 0, 128, 0, 0, 3, 176, 31, 0, 0, 2, 0, 0, 0, 144, + 0, 8, 15, 160, 66, 0, 0, 3, 0, 0, 15, 128, 0, 0, 228, 176, 0, 8, 228, + 160, 1, 0, 0, 2, 1, 0, 9, 128, 0, 0, 228, 160, 4, 0, 0, 4, 0, 0, + 1, 128, 0, 0, 0, 128, 1, 0, 0, 128, 1, 0, 0, 160, 4, 0, 0, 4, 0, + 0, 2, 128, 0, 0, 255, 128, 1, 0, 255, 128, 1, 0, 255, 160, 1, 0, 0, 2, + 1, 0, 7, 128, 0, 0, 0, 128, 1, 0, 0, 2, 1, 0, 8, 128, 0, 0, 85, + 128, 1, 0, 0, 2, 0, 8, 15, 128, 1, 0, 228, 128, 255, 255, 0, 0}; diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceunmultps.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceunmultps.h new file mode 100644 index 0000000000..1100d0b088 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceunmultps.h @@ -0,0 +1,54 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// +// Parameters: +// +// float4 add; +// float4 mult; +// sampler2D tex; +// +// +// Registers: +// +// Name Reg Size +// ------------ ----- ---- +// mult c0 1 +// add c1 1 +// tex s0 1 +// + + ps_2_0 + dcl t0.xy + dcl_2d s0 + texld r0, t0, s0 + rcp r1.w, r0.w + mul r1.x, r0.x, r1.w + cmp r0.xyz, -r0.w, r0.x, r1.x + mov r1, c0 + mad r0, r0, r1, c1 + mov oC0, r0 + +// approximately 7 instruction slots used (1 texture, 6 arithmetic) +#endif + +const BYTE g_ps20_luminanceunmultps[] = { + 0, 2, 255, 255, 254, 255, 50, 0, 67, 84, 65, 66, 28, 0, 0, 0, 143, 0, 0, + 0, 0, 2, 255, 255, 3, 0, 0, 0, 28, 0, 0, 0, 0, 1, 0, 0, 136, 0, + 0, 0, 88, 0, 0, 0, 2, 0, 1, 0, 1, 0, 0, 0, 92, 0, 0, 0, 0, + 0, 0, 0, 108, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 92, 0, 0, 0, + 0, 0, 0, 0, 113, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 120, 0, 0, + 0, 0, 0, 0, 0, 97, 100, 100, 0, 1, 0, 3, 0, 1, 0, 4, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 109, 117, 108, 116, 0, 116, 101, 120, 0, 171, 171, 171, 4, + 0, 12, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 112, 115, 95, 50, + 95, 48, 0, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 72, 76, + 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, + 54, 46, 51, 46, 57, 54, 48, 48, 46, 49, 54, 51, 56, 52, 0, 171, 171, 171, 31, + 0, 0, 2, 0, 0, 0, 128, 0, 0, 3, 176, 31, 0, 0, 2, 0, 0, 0, 144, + 0, 8, 15, 160, 66, 0, 0, 3, 0, 0, 15, 128, 0, 0, 228, 176, 0, 8, 228, + 160, 6, 0, 0, 2, 1, 0, 8, 128, 0, 0, 255, 128, 5, 0, 0, 3, 1, 0, + 1, 128, 0, 0, 0, 128, 1, 0, 255, 128, 88, 0, 0, 4, 0, 0, 7, 128, 0, + 0, 255, 129, 0, 0, 0, 128, 1, 0, 0, 128, 1, 0, 0, 2, 1, 0, 15, 128, + 0, 0, 228, 160, 4, 0, 0, 4, 0, 0, 15, 128, 0, 0, 228, 128, 1, 0, 228, + 128, 1, 0, 228, 160, 1, 0, 0, 2, 0, 8, 15, 128, 0, 0, 228, 128, 255, 255, + 0, 0}; diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/passthroughps.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/passthroughps.h new file mode 100644 index 0000000000..0c17739e17 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/passthroughps.h @@ -0,0 +1,37 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// +// Parameters: +// +// sampler2D tex; +// +// +// Registers: +// +// Name Reg Size +// ------------ ----- ---- +// tex s0 1 +// + + ps_2_0 + dcl t0.xy + dcl_2d s0 + texld r0, t0, s0 + mov oC0, r0 + +// approximately 2 instruction slots used (1 texture, 1 arithmetic) +#endif + +const BYTE g_ps20_passthroughps[] = { + 0, 2, 255, 255, 254, 255, 33, 0, 67, 84, 65, 66, 28, 0, 0, 0, 75, 0, + 0, 0, 0, 2, 255, 255, 1, 0, 0, 0, 28, 0, 0, 0, 0, 1, 0, 0, + 68, 0, 0, 0, 48, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 52, 0, + 0, 0, 0, 0, 0, 0, 116, 101, 120, 0, 4, 0, 12, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 112, 115, 95, 50, 95, 48, 0, 77, 105, 99, + 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 72, 76, 83, 76, 32, 83, 104, + 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, 54, 46, 51, 46, + 57, 54, 48, 48, 46, 49, 54, 51, 56, 52, 0, 171, 171, 171, 31, 0, 0, 2, + 0, 0, 0, 128, 0, 0, 3, 176, 31, 0, 0, 2, 0, 0, 0, 144, 0, 8, + 15, 160, 66, 0, 0, 3, 0, 0, 15, 128, 0, 0, 228, 176, 0, 8, 228, 160, + 1, 0, 0, 2, 0, 8, 15, 128, 0, 0, 228, 128, 255, 255, 0, 0}; diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/standardvs.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/standardvs.h new file mode 100644 index 0000000000..e4d7e0e1a8 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/shaders/compiled/standardvs.h @@ -0,0 +1,46 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// +// Parameters: +// +// float4 halfPixelSize; +// float4 texcoordOffset; +// +// +// Registers: +// +// Name Reg Size +// -------------- ----- ---- +// halfPixelSize c0 1 +// texcoordOffset c1 1 +// + + vs_2_0 + def c2, 0.5, -0.5, 1, 0 + dcl_position v0 + add oPos, v0, c0 + mad r0, v0, c2.xyzz, c2.xxww + mov oT0.zw, r0 + mad oT0.xy, r0, c1.zwzw, c1 + +// approximately 4 instruction slots used +#endif + +const BYTE g_vs20_standardvs[] = { + 0, 2, 254, 255, 254, 255, 44, 0, 67, 84, 65, 66, 28, 0, 0, 0, 122, 0, 0, + 0, 0, 2, 254, 255, 2, 0, 0, 0, 28, 0, 0, 0, 0, 1, 0, 0, 115, 0, + 0, 0, 68, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 84, 0, 0, 0, 0, + 0, 0, 0, 100, 0, 0, 0, 2, 0, 1, 0, 1, 0, 0, 0, 84, 0, 0, 0, + 0, 0, 0, 0, 104, 97, 108, 102, 80, 105, 120, 101, 108, 83, 105, 122, 101, 0, 171, + 171, 1, 0, 3, 0, 1, 0, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 116, 101, + 120, 99, 111, 111, 114, 100, 79, 102, 102, 115, 101, 116, 0, 118, 115, 95, 50, 95, 48, + 0, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 72, 76, 83, 76, + 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, 54, 46, + 51, 46, 57, 54, 48, 48, 46, 49, 54, 51, 56, 52, 0, 81, 0, 0, 5, 2, 0, + 15, 160, 0, 0, 0, 63, 0, 0, 0, 191, 0, 0, 128, 63, 0, 0, 0, 0, 31, + 0, 0, 2, 0, 0, 0, 128, 0, 0, 15, 144, 2, 0, 0, 3, 0, 0, 15, 192, + 0, 0, 228, 144, 0, 0, 228, 160, 4, 0, 0, 4, 0, 0, 15, 128, 0, 0, 228, + 144, 2, 0, 164, 160, 2, 0, 240, 160, 1, 0, 0, 2, 0, 0, 12, 224, 0, 0, + 228, 128, 4, 0, 0, 4, 0, 0, 3, 224, 0, 0, 228, 128, 1, 0, 238, 160, 1, + 0, 228, 160, 255, 255, 0, 0}; diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h new file mode 100644 index 0000000000..8a702bcb61 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h @@ -0,0 +1,197 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// vertexconversion.h: A library of vertex conversion classes that can be used to build +// the FormatConverter objects used by the buffer conversion system. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXCONVERSION_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXCONVERSION_H_ + +#include <cstddef> +#include <cstdint> +#include <limits> + +namespace rx +{ + +// Conversion types: +// static const bool identity: true if this is an identity transform, false otherwise +// static U convert(T): convert a single element from the input type to the output type +// typedef ... OutputType: the type produced by this conversion + +template <class T> +struct Identity +{ + static const bool identity = true; + + typedef T OutputType; + + static T convert(T x) { return x; } +}; + +template <class FromT, class ToT> +struct Cast +{ + static const bool identity = false; + + typedef ToT OutputType; + + static ToT convert(FromT x) { return static_cast<ToT>(x); } +}; + +template <class T> +struct Cast<T, T> +{ + static const bool identity = true; + + typedef T OutputType; + + static T convert(T x) { return static_cast<T>(x); } +}; + +template <class T> +struct Normalize +{ + static const bool identity = false; + + typedef float OutputType; + + static float convert(T x) + { + typedef std::numeric_limits<T> NL; + float f = static_cast<float>(x); + + if (NL::is_signed) + { + // const float => VC2008 computes it at compile time + // static const float => VC2008 computes it the first time we get here, stores it to + // memory with static guard and all that. + const float divisor = 1.0f / (2 * static_cast<float>(NL::max()) + 1); + return (2 * f + 1) * divisor; + } + else + { + return f / NL::max(); + } + } +}; + +template <class FromType, std::size_t ScaleBits> +struct FixedToFloat +{ + static const bool identity = false; + + typedef float OutputType; + + static float convert(FromType x) + { + const float divisor = 1.0f / static_cast<float>(static_cast<FromType>(1) << ScaleBits); + return static_cast<float>(x) * divisor; + } +}; + +// Widen types: +// static const unsigned int initialWidth: number of components before conversion +// static const unsigned int finalWidth: number of components after conversion + +// Float is supported at any size. +template <std::size_t N> +struct NoWiden +{ + static const std::size_t initialWidth = N; + static const std::size_t finalWidth = N; +}; + +// SHORT, norm-SHORT, norm-UNSIGNED_SHORT are supported but only with 2 or 4 components +template <std::size_t N> +struct WidenToEven +{ + static const std::size_t initialWidth = N; + static const std::size_t finalWidth = N + (N & 1); +}; + +template <std::size_t N> +struct WidenToFour +{ + static const std::size_t initialWidth = N; + static const std::size_t finalWidth = 4; +}; + +// Most types have 0 and 1 that are just that. +template <class T> +struct SimpleDefaultValues +{ + static T zero() { return static_cast<T>(0); } + static T one() { return static_cast<T>(1); } +}; + +// But normalised types only store [0,1] or [-1,1] so 1.0 is represented by the max value. +template <class T> +struct NormalizedDefaultValues +{ + static T zero() { return static_cast<T>(0); } + static T one() { return std::numeric_limits<T>::max(); } +}; + +// Converter: +// static const bool identity: true if this is an identity transform (with no widening) +// static const std::size_t finalSize: number of bytes per output vertex +// static void convertArray(const void *in, std::size_t stride, std::size_t n, void *out): convert +// an array of vertices. Input may be strided, but output will be unstrided. + +template <class InT, + class WidenRule, + class Converter, + class DefaultValueRule = SimpleDefaultValues<InT>> +struct VertexDataConverter +{ + typedef typename Converter::OutputType OutputType; + typedef InT InputType; + + static const bool identity = + (WidenRule::initialWidth == WidenRule::finalWidth) && Converter::identity; + static const std::size_t finalSize = WidenRule::finalWidth * sizeof(OutputType); + + static void convertArray(const uint8_t *input, size_t stride, size_t n, uint8_t *output) + { + OutputType *out = reinterpret_cast<OutputType *>(output); + + for (std::size_t i = 0; i < n; i++) + { + const InputType *ein = reinterpret_cast<const InputType *>(input + i * stride); + + copyComponent(out, ein, 0, static_cast<OutputType>(DefaultValueRule::zero())); + copyComponent(out, ein, 1, static_cast<OutputType>(DefaultValueRule::zero())); + copyComponent(out, ein, 2, static_cast<OutputType>(DefaultValueRule::zero())); + copyComponent(out, ein, 3, static_cast<OutputType>(DefaultValueRule::one())); + + out += WidenRule::finalWidth; + } + } + + private: + static void copyComponent(OutputType *out, + const InputType *in, + std::size_t elementindex, + OutputType defaultvalue) + { + if (WidenRule::finalWidth > elementindex) + { + if (WidenRule::initialWidth > elementindex) + { + out[elementindex] = Converter::convert(in[elementindex]); + } + else + { + out[elementindex] = defaultvalue; + } + } + } +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXCONVERSION_H_ |