diff options
Diffstat (limited to 'src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11')
42 files changed, 15650 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp new file mode 100644 index 0000000000..9b0f336ac7 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp @@ -0,0 +1,1049 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Blit11.cpp: Texture copy utility class. + +#include "libGLESv2/main.h" +#include "libGLESv2/formatutils.h" +#include "libGLESv2/renderer/d3d/d3d11/Blit11.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" + +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough2dvs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughdepth2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2duips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2duips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2dips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg2duips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg2dips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr2duips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr2dips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlum2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha2dps.h" + +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough3dvs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough3dgs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3duips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3dips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3duips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3dips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg3dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg3duips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg3dips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr3dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr3duips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr3dips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlum3dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha3dps.h" + +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlef2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlei2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzleui2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlef3dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlei3dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzleui3dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlef2darrayps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlei2darrayps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzleui2darrayps.h" + +namespace rx +{ + +static DXGI_FORMAT GetTextureFormat(ID3D11Resource *resource) +{ + ID3D11Texture2D *texture = d3d11::DynamicCastComObject<ID3D11Texture2D>(resource); + if (!texture) + { + return DXGI_FORMAT_UNKNOWN; + } + + D3D11_TEXTURE2D_DESC desc; + texture->GetDesc(&desc); + + SafeRelease(texture); + + return desc.Format; +} + +static ID3D11Resource *CreateStagingTexture(ID3D11Device *device, ID3D11DeviceContext *context, + ID3D11Resource *source, unsigned int subresource, + const gl::Extents &size, unsigned int cpuAccessFlags) +{ + D3D11_TEXTURE2D_DESC stagingDesc; + stagingDesc.Width = size.width; + stagingDesc.Height = size.height; + stagingDesc.MipLevels = 1; + stagingDesc.ArraySize = 1; + stagingDesc.Format = GetTextureFormat(source); + stagingDesc.SampleDesc.Count = 1; + stagingDesc.SampleDesc.Quality = 0; + stagingDesc.Usage = D3D11_USAGE_STAGING; + stagingDesc.CPUAccessFlags = cpuAccessFlags; + stagingDesc.MiscFlags = 0; + stagingDesc.BindFlags = 0; + + ID3D11Texture2D *stagingTexture = NULL; + HRESULT result = device->CreateTexture2D(&stagingDesc, NULL, &stagingTexture); + if (FAILED(result)) + { + ERR("Failed to create staging texture for depth stencil blit. HRESULT: 0x%X.", result); + return NULL; + } + + context->CopySubresourceRegion(stagingTexture, 0, 0, 0, 0, source, subresource, NULL); + + return stagingTexture; +} + +inline static void GenerateVertexCoords(const gl::Box &sourceArea, const gl::Extents &sourceSize, + const gl::Box &destArea, const gl::Extents &destSize, + float *x1, float *y1, float *x2, float *y2, + float *u1, float *v1, float *u2, float *v2) +{ + *x1 = (destArea.x / float(destSize.width)) * 2.0f - 1.0f; + *y1 = ((destSize.height - destArea.y - destArea.height) / float(destSize.height)) * 2.0f - 1.0f; + *x2 = ((destArea.x + destArea.width) / float(destSize.width)) * 2.0f - 1.0f; + *y2 = ((destSize.height - destArea.y) / float(destSize.height)) * 2.0f - 1.0f; + + *u1 = sourceArea.x / float(sourceSize.width); + *v1 = sourceArea.y / float(sourceSize.height); + *u2 = (sourceArea.x + sourceArea.width) / float(sourceSize.width); + *v2 = (sourceArea.y + sourceArea.height) / float(sourceSize.height); +} + +static void Write2DVertices(const gl::Box &sourceArea, const gl::Extents &sourceSize, + const gl::Box &destArea, const gl::Extents &destSize, + void *outVertices, unsigned int *outStride, unsigned int *outVertexCount, + D3D11_PRIMITIVE_TOPOLOGY *outTopology) +{ + float x1, y1, x2, y2, u1, v1, u2, v2; + GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, &u2, &v2); + + d3d11::PositionTexCoordVertex *vertices = static_cast<d3d11::PositionTexCoordVertex*>(outVertices); + + d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v2); + d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v1); + d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v2); + d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v1); + + *outStride = sizeof(d3d11::PositionTexCoordVertex); + *outVertexCount = 4; + *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; +} + +static void Write3DVertices(const gl::Box &sourceArea, const gl::Extents &sourceSize, + const gl::Box &destArea, const gl::Extents &destSize, + void *outVertices, unsigned int *outStride, unsigned int *outVertexCount, + D3D11_PRIMITIVE_TOPOLOGY *outTopology) +{ + ASSERT(sourceSize.depth > 0 && destSize.depth > 0); + + float x1, y1, x2, y2, u1, v1, u2, v2; + GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, &u2, &v2); + + d3d11::PositionLayerTexCoord3DVertex *vertices = static_cast<d3d11::PositionLayerTexCoord3DVertex*>(outVertices); + + for (int i = 0; i < destSize.depth; i++) + { + float readDepth = (float)i / std::max(destSize.depth - 1, 1); + + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 0], x1, y1, i, u1, v2, readDepth); + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 1], x1, y2, i, u1, v1, readDepth); + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 2], x2, y1, i, u2, v2, readDepth); + + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 3], x1, y2, i, u1, v1, readDepth); + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 4], x2, y2, i, u2, v1, readDepth); + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 5], x2, y1, i, u2, v2, readDepth); + } + + *outStride = sizeof(d3d11::PositionLayerTexCoord3DVertex); + *outVertexCount = destSize.depth * 6; + *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; +} + +Blit11::Blit11(rx::Renderer11 *renderer) + : mRenderer(renderer), mBlitShaderMap(compareBlitParameters), mSwizzleShaderMap(compareSwizzleParameters), + mVertexBuffer(NULL), mPointSampler(NULL), mLinearSampler(NULL), mScissorEnabledRasterizerState(NULL), + mScissorDisabledRasterizerState(NULL), mDepthStencilState(NULL), + mQuad2DIL(NULL), mQuad2DVS(NULL), mDepthPS(NULL), + mQuad3DIL(NULL), mQuad3DVS(NULL), mQuad3DGS(NULL), + mSwizzleCB(NULL) +{ + HRESULT result; + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_BUFFER_DESC vbDesc; + vbDesc.ByteWidth = std::max(sizeof(d3d11::PositionLayerTexCoord3DVertex), sizeof(d3d11::PositionTexCoordVertex)) * + 6 * renderer->getRendererCaps().max3DTextureSize; + vbDesc.Usage = D3D11_USAGE_DYNAMIC; + vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + vbDesc.MiscFlags = 0; + vbDesc.StructureByteStride = 0; + + result = device->CreateBuffer(&vbDesc, NULL, &mVertexBuffer); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mVertexBuffer, "Blit11 vertex buffer"); + + D3D11_SAMPLER_DESC pointSamplerDesc; + pointSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; + pointSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + pointSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + pointSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + pointSamplerDesc.MipLODBias = 0.0f; + pointSamplerDesc.MaxAnisotropy = 0; + pointSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + pointSamplerDesc.BorderColor[0] = 0.0f; + pointSamplerDesc.BorderColor[1] = 0.0f; + pointSamplerDesc.BorderColor[2] = 0.0f; + pointSamplerDesc.BorderColor[3] = 0.0f; + pointSamplerDesc.MinLOD = 0.0f; + pointSamplerDesc.MaxLOD = mRenderer->isLevel9() ? FLT_MAX : 0.0f; + + result = device->CreateSamplerState(&pointSamplerDesc, &mPointSampler); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mPointSampler, "Blit11 point sampler"); + + D3D11_SAMPLER_DESC linearSamplerDesc; + linearSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + linearSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.MipLODBias = 0.0f; + linearSamplerDesc.MaxAnisotropy = 0; + linearSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + linearSamplerDesc.BorderColor[0] = 0.0f; + linearSamplerDesc.BorderColor[1] = 0.0f; + linearSamplerDesc.BorderColor[2] = 0.0f; + linearSamplerDesc.BorderColor[3] = 0.0f; + linearSamplerDesc.MinLOD = 0.0f; + linearSamplerDesc.MaxLOD = mRenderer->isLevel9() ? FLT_MAX : 0.0f; + + result = device->CreateSamplerState(&linearSamplerDesc, &mLinearSampler); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mLinearSampler, "Blit11 linear sampler"); + + // Use a rasterizer state that will not cull so that inverted quads will not be culled + D3D11_RASTERIZER_DESC rasterDesc; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.CullMode = D3D11_CULL_NONE; + rasterDesc.FrontCounterClockwise = FALSE; + rasterDesc.DepthBias = 0; + rasterDesc.SlopeScaledDepthBias = 0.0f; + rasterDesc.DepthBiasClamp = 0.0f; + rasterDesc.DepthClipEnable = TRUE; + rasterDesc.MultisampleEnable = FALSE; + rasterDesc.AntialiasedLineEnable = FALSE; + + rasterDesc.ScissorEnable = TRUE; + result = device->CreateRasterizerState(&rasterDesc, &mScissorEnabledRasterizerState); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mScissorEnabledRasterizerState, "Blit11 scissoring rasterizer state"); + + rasterDesc.ScissorEnable = FALSE; + result = device->CreateRasterizerState(&rasterDesc, &mScissorDisabledRasterizerState); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mScissorDisabledRasterizerState, "Blit11 no scissoring rasterizer state"); + + D3D11_DEPTH_STENCIL_DESC depthStencilDesc; + depthStencilDesc.DepthEnable = true; + depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + depthStencilDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.StencilEnable = FALSE; + depthStencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + depthStencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + + result = device->CreateDepthStencilState(&depthStencilDesc, &mDepthStencilState); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mDepthStencilState, "Blit11 depth stencil state"); + + D3D11_INPUT_ELEMENT_DESC quad2DLayout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + result = device->CreateInputLayout(quad2DLayout, ArraySize(quad2DLayout), g_VS_Passthrough2D, ArraySize(g_VS_Passthrough2D), &mQuad2DIL); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad2DIL, "Blit11 2D input layout"); + + result = device->CreateVertexShader(g_VS_Passthrough2D, ArraySize(g_VS_Passthrough2D), NULL, &mQuad2DVS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad2DVS, "Blit11 2D vertex shader"); + + if (!renderer->isLevel9()) + { + result = device->CreatePixelShader(g_PS_PassthroughDepth2D, ArraySize(g_PS_PassthroughDepth2D), NULL, &mDepthPS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mDepthPS, "Blit11 2D depth pixel shader"); + + D3D11_INPUT_ELEMENT_DESC quad3DLayout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "LAYER", 0, DXGI_FORMAT_R32_UINT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + result = device->CreateInputLayout(quad3DLayout, ArraySize(quad3DLayout), g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), &mQuad3DIL); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad3DIL, "Blit11 3D input layout"); + + result = device->CreateVertexShader(g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), NULL, &mQuad3DVS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad3DVS, "Blit11 3D vertex shader"); + + result = device->CreateGeometryShader(g_GS_Passthrough3D, ArraySize(g_GS_Passthrough3D), NULL, &mQuad3DGS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad3DGS, "Renderer11 copy 3D texture geometry shader"); + + } + + buildShaderMap(); + + D3D11_BUFFER_DESC swizzleBufferDesc; + swizzleBufferDesc.ByteWidth = sizeof(unsigned int) * 4; + swizzleBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + swizzleBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + swizzleBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + swizzleBufferDesc.MiscFlags = 0; + swizzleBufferDesc.StructureByteStride = 0; + + result = device->CreateBuffer(&swizzleBufferDesc, NULL, &mSwizzleCB); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mSwizzleCB, "Blit11 swizzle constant buffer"); +} + +Blit11::~Blit11() +{ + SafeRelease(mVertexBuffer); + SafeRelease(mPointSampler); + SafeRelease(mLinearSampler); + SafeRelease(mScissorEnabledRasterizerState); + SafeRelease(mScissorDisabledRasterizerState); + SafeRelease(mDepthStencilState); + + SafeRelease(mQuad2DIL); + SafeRelease(mQuad2DVS); + SafeRelease(mDepthPS); + + SafeRelease(mQuad3DIL); + SafeRelease(mQuad3DVS); + SafeRelease(mQuad3DGS); + + SafeRelease(mSwizzleCB); + + clearShaderMap(); +} + +static inline unsigned int GetSwizzleIndex(GLenum swizzle) +{ + unsigned int colorIndex = 0; + + switch (swizzle) + { + case GL_RED: colorIndex = 0; break; + case GL_GREEN: colorIndex = 1; break; + case GL_BLUE: colorIndex = 2; break; + case GL_ALPHA: colorIndex = 3; break; + case GL_ZERO: colorIndex = 4; break; + case GL_ONE: colorIndex = 5; break; + default: UNREACHABLE(); break; + } + + return colorIndex; +} + +bool Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderTargetView *dest, const gl::Extents &size, + GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) +{ + HRESULT result; + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; + source->GetDesc(&sourceSRVDesc); + GLenum sourceInternalFormat = d3d11_gl::GetInternalFormat(sourceSRVDesc.Format); + + GLenum shaderType = GL_NONE; + switch (gl::GetComponentType(sourceInternalFormat)) + { + case GL_UNSIGNED_NORMALIZED: + case GL_SIGNED_NORMALIZED: + case GL_FLOAT: + shaderType = GL_FLOAT; + break; + case GL_INT: + shaderType = GL_INT; + break; + case GL_UNSIGNED_INT: + shaderType = GL_UNSIGNED_INT; + break; + default: + UNREACHABLE(); + break; + } + + SwizzleParameters parameters = { 0 }; + parameters.mDestinationType = shaderType; + parameters.mViewDimension = sourceSRVDesc.ViewDimension; + + SwizzleShaderMap::const_iterator i = mSwizzleShaderMap.find(parameters); + if (i == mSwizzleShaderMap.end()) + { + UNREACHABLE(); + return false; + } + + const Shader &shader = i->second; + + // Set vertices + D3D11_MAPPED_SUBRESOURCE mappedResource; + result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + ERR("Failed to map vertex buffer for texture swizzle, HRESULT: 0x%X.", result); + return false; + } + + UINT stride = 0; + UINT startIdx = 0; + UINT drawCount = 0; + D3D11_PRIMITIVE_TOPOLOGY topology; + + gl::Box area(0, 0, 0, size.width, size.height, size.depth); + shader.mVertexWriteFunction(area, size, area, size, mappedResource.pData, &stride, &drawCount, &topology); + + deviceContext->Unmap(mVertexBuffer, 0); + + // Set constant buffer + result = deviceContext->Map(mSwizzleCB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + ERR("Failed to map constant buffer for texture swizzle, HRESULT: 0x%X.", result); + return false; + } + + unsigned int *swizzleIndices = reinterpret_cast<unsigned int*>(mappedResource.pData); + swizzleIndices[0] = GetSwizzleIndex(swizzleRed); + swizzleIndices[1] = GetSwizzleIndex(swizzleGreen); + swizzleIndices[2] = GetSwizzleIndex(swizzleBlue); + swizzleIndices[3] = GetSwizzleIndex(swizzleAlpha); + + deviceContext->Unmap(mSwizzleCB, 0); + + // Apply vertex buffer + deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + + // Apply constant buffer + deviceContext->PSSetConstantBuffers(0, 1, &mSwizzleCB); + + // Apply state + deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); + deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); + deviceContext->RSSetState(mScissorDisabledRasterizerState); + + // Apply shaders + deviceContext->IASetInputLayout(shader.mInputLayout); + deviceContext->IASetPrimitiveTopology(topology); + deviceContext->VSSetShader(shader.mVertexShader, NULL, 0); + + deviceContext->PSSetShader(shader.mPixelShader, NULL, 0); + deviceContext->GSSetShader(shader.mGeometryShader, NULL, 0); + + // Unset the currently bound shader resource to avoid conflicts + ID3D11ShaderResourceView *const nullSRV = NULL; + deviceContext->PSSetShaderResources(0, 1, &nullSRV); + + // Apply render target + mRenderer->setOneTimeRenderTarget(dest); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = size.width; + viewport.Height = size.height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + // Apply textures + deviceContext->PSSetShaderResources(0, 1, &source); + + // Apply samplers + deviceContext->PSSetSamplers(0, 1, &mPointSampler); + + // Draw the quad + deviceContext->Draw(drawCount, 0); + + // Unbind textures and render targets and vertex buffer + deviceContext->PSSetShaderResources(0, 1, &nullSRV); + + mRenderer->unapplyRenderTargets(); + + UINT zero = 0; + ID3D11Buffer *const nullBuffer = NULL; + deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + + mRenderer->markAllStateDirty(); + + return true; +} + +bool Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, GLenum destFormat, GLenum filter) +{ + HRESULT result; + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + // Determine if the source format is a signed integer format, the destFormat will already + // be GL_XXXX_INTEGER but it does not tell us if it is signed or unsigned. + D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; + source->GetDesc(&sourceSRVDesc); + GLenum sourceInternalFormat = d3d11_gl::GetInternalFormat(sourceSRVDesc.Format); + + BlitParameters parameters = { 0 }; + parameters.mDestinationFormat = destFormat; + parameters.mSignedInteger = gl::GetComponentType(sourceInternalFormat) == GL_INT; + parameters.m3DBlit = sourceArea.depth > 1; + + BlitShaderMap::const_iterator i = mBlitShaderMap.find(parameters); + if (i == mBlitShaderMap.end()) + { + UNREACHABLE(); + return false; + } + + const Shader& shader = i->second; + + // Set vertices + D3D11_MAPPED_SUBRESOURCE mappedResource; + result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + ERR("Failed to map vertex buffer for texture copy, HRESULT: 0x%X.", result); + return false; + } + + UINT stride = 0; + UINT startIdx = 0; + UINT drawCount = 0; + D3D11_PRIMITIVE_TOPOLOGY topology; + + shader.mVertexWriteFunction(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, + &stride, &drawCount, &topology); + + deviceContext->Unmap(mVertexBuffer, 0); + + // Apply vertex buffer + deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + + // Apply state + deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); + deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); + + if (scissor) + { + D3D11_RECT scissorRect; + scissorRect.left = scissor->x; + scissorRect.right = scissor->x + scissor->width; + scissorRect.top = scissor->y; + scissorRect.bottom = scissor->y + scissor->height; + + deviceContext->RSSetScissorRects(1, &scissorRect); + deviceContext->RSSetState(mScissorEnabledRasterizerState); + } + else + { + deviceContext->RSSetState(mScissorDisabledRasterizerState); + } + + // Apply shaders + deviceContext->IASetInputLayout(shader.mInputLayout); + deviceContext->IASetPrimitiveTopology(topology); + deviceContext->VSSetShader(shader.mVertexShader, NULL, 0); + + deviceContext->PSSetShader(shader.mPixelShader, NULL, 0); + deviceContext->GSSetShader(shader.mGeometryShader, NULL, 0); + + // Unset the currently bound shader resource to avoid conflicts + ID3D11ShaderResourceView *const nullSRV = NULL; + deviceContext->PSSetShaderResources(0, 1, &nullSRV); + + // Apply render target + mRenderer->setOneTimeRenderTarget(dest); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = destSize.width; + viewport.Height = destSize.height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + // Apply textures + deviceContext->PSSetShaderResources(0, 1, &source); + + // Apply samplers + ID3D11SamplerState *sampler = NULL; + switch (filter) + { + case GL_NEAREST: sampler = mPointSampler; break; + case GL_LINEAR: sampler = mLinearSampler; break; + default: UNREACHABLE(); return false; + } + deviceContext->PSSetSamplers(0, 1, &sampler); + + // Draw the quad + deviceContext->Draw(drawCount, 0); + + // Unbind textures and render targets and vertex buffer + deviceContext->PSSetShaderResources(0, 1, &nullSRV); + + mRenderer->unapplyRenderTargets(); + + UINT zero = 0; + ID3D11Buffer *const nullBuffer = NULL; + deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + + mRenderer->markAllStateDirty(); + + return true; +} + +bool Blit11::copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor) +{ + return copyDepthStencil(source, sourceSubresource, sourceArea, sourceSize, + dest, destSubresource, destArea, destSize, + scissor, true); +} + +bool Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor) +{ + HRESULT result; + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + // Set vertices + D3D11_MAPPED_SUBRESOURCE mappedResource; + result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + ERR("Failed to map vertex buffer for texture copy, HRESULT: 0x%X.", result); + return false; + } + + UINT stride = 0; + UINT startIdx = 0; + UINT drawCount = 0; + D3D11_PRIMITIVE_TOPOLOGY topology; + + Write2DVertices(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, + &stride, &drawCount, &topology); + + deviceContext->Unmap(mVertexBuffer, 0); + + // Apply vertex buffer + deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + + // Apply state + deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); + deviceContext->OMSetDepthStencilState(mDepthStencilState, 0xFFFFFFFF); + + if (scissor) + { + D3D11_RECT scissorRect; + scissorRect.left = scissor->x; + scissorRect.right = scissor->x + scissor->width; + scissorRect.top = scissor->y; + scissorRect.bottom = scissor->y + scissor->height; + + deviceContext->RSSetScissorRects(1, &scissorRect); + deviceContext->RSSetState(mScissorEnabledRasterizerState); + } + else + { + deviceContext->RSSetState(mScissorDisabledRasterizerState); + } + + // Apply shaders + deviceContext->IASetInputLayout(mQuad2DIL); + deviceContext->IASetPrimitiveTopology(topology); + deviceContext->VSSetShader(mQuad2DVS, NULL, 0); + + deviceContext->PSSetShader(mDepthPS, NULL, 0); + deviceContext->GSSetShader(NULL, NULL, 0); + + // Unset the currently bound shader resource to avoid conflicts + ID3D11ShaderResourceView *const nullSRV = NULL; + deviceContext->PSSetShaderResources(0, 1, &nullSRV); + + // Apply render target + deviceContext->OMSetRenderTargets(0, NULL, dest); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = destSize.width; + viewport.Height = destSize.height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + // Apply textures + deviceContext->PSSetShaderResources(0, 1, &source); + + // Apply samplers + deviceContext->PSSetSamplers(0, 1, &mPointSampler); + + // Draw the quad + deviceContext->Draw(drawCount, 0); + + // Unbind textures and render targets and vertex buffer + deviceContext->PSSetShaderResources(0, 1, &nullSRV); + + mRenderer->unapplyRenderTargets(); + + UINT zero = 0; + ID3D11Buffer *const nullBuffer = NULL; + deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + + mRenderer->markAllStateDirty(); + + return true; +} + +bool Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor) +{ + return copyDepthStencil(source, sourceSubresource, sourceArea, sourceSize, + dest, destSubresource, destArea, destSize, + scissor, false); +} + +bool Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, bool stencilOnly) +{ + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + ID3D11Resource *sourceStaging = CreateStagingTexture(device, deviceContext, source, sourceSubresource, sourceSize, D3D11_CPU_ACCESS_READ); + // HACK: Create the destination staging buffer as a read/write texture so ID3D11DevicContext::UpdateSubresource can be called + // using it's mapped data as a source + ID3D11Resource *destStaging = CreateStagingTexture(device, deviceContext, dest, destSubresource, destSize, D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE); + + if (!sourceStaging || !destStaging) + { + SafeRelease(sourceStaging); + SafeRelease(destStaging); + return false; + } + + DXGI_FORMAT format = GetTextureFormat(source); + ASSERT(format == GetTextureFormat(dest)); + + unsigned int pixelSize = d3d11::GetFormatPixelBytes(format); + unsigned int copyOffset = 0; + unsigned int copySize = pixelSize; + if (stencilOnly) + { + copyOffset = d3d11::GetStencilOffset(format) / 8; + copySize = d3d11::GetStencilBits(format) / 8; + + // It would be expensive to have non-byte sized stencil sizes since it would + // require reading from the destination, currently there aren't any though. + ASSERT(d3d11::GetStencilBits(format) % 8 == 0 && + d3d11::GetStencilOffset(format) % 8 == 0); + } + + D3D11_MAPPED_SUBRESOURCE sourceMapping, destMapping; + deviceContext->Map(sourceStaging, 0, D3D11_MAP_READ, 0, &sourceMapping); + deviceContext->Map(destStaging, 0, D3D11_MAP_WRITE, 0, &destMapping); + + if (!sourceMapping.pData || !destMapping.pData) + { + if (!sourceMapping.pData) + { + deviceContext->Unmap(sourceStaging, 0); + } + if (!destMapping.pData) + { + deviceContext->Unmap(destStaging, 0); + } + SafeRelease(sourceStaging); + SafeRelease(destStaging); + return false; + } + + gl::Rectangle clippedDestArea(destArea.x, destArea.y, destArea.width, destArea.height); + + // Clip dest area to the destination size + gl::ClipRectangle(clippedDestArea, gl::Rectangle(0, 0, destSize.width, destSize.height), &clippedDestArea); + + // Clip dest area to the scissor + if (scissor) + { + gl::ClipRectangle(clippedDestArea, *scissor, &clippedDestArea); + } + + // Determine if entire rows can be copied at once instead of each individual pixel, requires that there is + // no out of bounds lookups required, the entire pixel is copied and no stretching + bool wholeRowCopy = sourceArea.width == clippedDestArea.width && + sourceArea.x >= 0 && sourceArea.x + sourceArea.width <= sourceSize.width && + copySize == pixelSize; + + for (int y = clippedDestArea.y; y < clippedDestArea.y + clippedDestArea.height; y++) + { + float yPerc = static_cast<float>(y - destArea.y) / (destArea.height - 1); + + // Interpolate using the original source rectangle to determine which row to sample from while clamping to the edges + unsigned int readRow = gl::clamp(sourceArea.y + floor(yPerc * (sourceArea.height - 1) + 0.5f), 0, sourceSize.height - 1); + unsigned int writeRow = y; + + if (wholeRowCopy) + { + void *sourceRow = reinterpret_cast<char*>(sourceMapping.pData) + + readRow * sourceMapping.RowPitch + + sourceArea.x * pixelSize; + + void *destRow = reinterpret_cast<char*>(destMapping.pData) + + writeRow * destMapping.RowPitch + + destArea.x * pixelSize; + + memcpy(destRow, sourceRow, pixelSize * destArea.width); + } + else + { + for (int x = clippedDestArea.x; x < clippedDestArea.x + clippedDestArea.width; x++) + { + float xPerc = static_cast<float>(x - destArea.x) / (destArea.width - 1); + + // Interpolate the original source rectangle to determine which column to sample from while clamping to the edges + unsigned int readColumn = gl::clamp(sourceArea.x + floor(xPerc * (sourceArea.width - 1) + 0.5f), 0, sourceSize.width - 1); + unsigned int writeColumn = x; + + void *sourcePixel = reinterpret_cast<char*>(sourceMapping.pData) + + readRow * sourceMapping.RowPitch + + readColumn * pixelSize + + copyOffset; + + void *destPixel = reinterpret_cast<char*>(destMapping.pData) + + writeRow * destMapping.RowPitch + + writeColumn * pixelSize + + copyOffset; + + memcpy(destPixel, sourcePixel, copySize); + } + } + } + + // HACK: Use ID3D11DevicContext::UpdateSubresource which causes an extra copy compared to ID3D11DevicContext::CopySubresourceRegion + // according to MSDN. + deviceContext->UpdateSubresource(dest, destSubresource, NULL, destMapping.pData, destMapping.RowPitch, destMapping.DepthPitch); + + deviceContext->Unmap(sourceStaging, 0); + deviceContext->Unmap(destStaging, 0); + + // TODO: Determine why this call to ID3D11DevicContext::CopySubresourceRegion causes a TDR timeout on some + // systems when called repeatedly. + // deviceContext->CopySubresourceRegion(dest, destSubresource, 0, 0, 0, destStaging, 0, NULL); + + SafeRelease(sourceStaging); + SafeRelease(destStaging); + + return true; +} + +bool Blit11::compareBlitParameters(const Blit11::BlitParameters &a, const Blit11::BlitParameters &b) +{ + return memcmp(&a, &b, sizeof(Blit11::BlitParameters)) < 0; +} + +bool Blit11::compareSwizzleParameters(const SwizzleParameters &a, const SwizzleParameters &b) +{ + return memcmp(&a, &b, sizeof(Blit11::SwizzleParameters)) < 0; +} + +void Blit11::add2DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps) +{ + BlitParameters params = { 0 }; + params.mDestinationFormat = destFormat; + params.mSignedInteger = signedInteger; + params.m3DBlit = false; + + ASSERT(mBlitShaderMap.find(params) == mBlitShaderMap.end()); + ASSERT(ps); + + Shader shader; + shader.mVertexWriteFunction = Write2DVertices; + shader.mInputLayout = mQuad2DIL; + shader.mVertexShader = mQuad2DVS; + shader.mGeometryShader = NULL; + shader.mPixelShader = ps; + + mBlitShaderMap[params] = shader; +} + +void Blit11::add3DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps) +{ + BlitParameters params = { 0 }; + params.mDestinationFormat = destFormat; + params.mSignedInteger = signedInteger; + params.m3DBlit = true; + + ASSERT(mBlitShaderMap.find(params) == mBlitShaderMap.end()); + ASSERT(ps); + + Shader shader; + shader.mVertexWriteFunction = Write3DVertices; + shader.mInputLayout = mQuad3DIL; + shader.mVertexShader = mQuad3DVS; + shader.mGeometryShader = mQuad3DGS; + shader.mPixelShader = ps; + + mBlitShaderMap[params] = shader; +} + +void Blit11::addSwizzleShaderToMap(GLenum destType, D3D11_SRV_DIMENSION viewDimension, ID3D11PixelShader *ps) +{ + SwizzleParameters params = { 0 }; + params.mDestinationType = destType; + params.mViewDimension = viewDimension; + + ASSERT(mSwizzleShaderMap.find(params) == mSwizzleShaderMap.end()); + ASSERT(ps); + + Shader shader; + switch (viewDimension) + { + case D3D_SRV_DIMENSION_TEXTURE2D: + shader.mVertexWriteFunction = Write2DVertices; + shader.mInputLayout = mQuad2DIL; + shader.mVertexShader = mQuad2DVS; + shader.mGeometryShader = NULL; + break; + + case D3D_SRV_DIMENSION_TEXTURE3D: + case D3D_SRV_DIMENSION_TEXTURE2DARRAY: + case D3D_SRV_DIMENSION_TEXTURECUBE: + shader.mVertexWriteFunction = Write3DVertices; + shader.mInputLayout = mQuad3DIL; + shader.mVertexShader = mQuad3DVS; + shader.mGeometryShader = mQuad3DGS; + break; + + default: + UNREACHABLE(); + break; + } + shader.mPixelShader = ps; + + mSwizzleShaderMap[params] = shader; +} + +void Blit11::buildShaderMap() +{ + ID3D11Device *device = mRenderer->getDevice(); + + add2DBlitShaderToMap(GL_RGBA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D RGBA pixel shader" )); + add2DBlitShaderToMap(GL_BGRA_EXT, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D BGRA pixel shader" )); + add2DBlitShaderToMap(GL_RGB, false, d3d11::CompilePS(device, g_PS_PassthroughRGB2D, "Blit11 2D RGB pixel shader" )); + add2DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG2D, "Blit11 2D RG pixel shader" )); + add2DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR2D, "Blit11 2D R pixel shader" )); + add2DBlitShaderToMap(GL_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D alpha pixel shader" )); + add2DBlitShaderToMap(GL_LUMINANCE, false, d3d11::CompilePS(device, g_PS_PassthroughLum2D, "Blit11 2D lum pixel shader" )); + add2DBlitShaderToMap(GL_LUMINANCE_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha2D, "Blit11 2D luminance alpha pixel shader")); + + addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleF2D, "Blit11 2D F swizzle pixel shader" )); + + if (mRenderer->isLevel9()) + return; + + add2DBlitShaderToMap(GL_RGBA_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DUI, "Blit11 2D RGBA UI pixel shader" )); + add2DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DI, "Blit11 2D RGBA I pixel shader" )); + add2DBlitShaderToMap(GL_RGB_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGB2DUI, "Blit11 2D RGB UI pixel shader" )); + add2DBlitShaderToMap(GL_RGB_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGB2DI, "Blit11 2D RGB I pixel shader" )); + add2DBlitShaderToMap(GL_RG_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRG2DUI, "Blit11 2D RG UI pixel shader" )); + add2DBlitShaderToMap(GL_RG_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRG2DI, "Blit11 2D RG I pixel shader" )); + add2DBlitShaderToMap(GL_RED_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughR2DUI, "Blit11 2D R UI pixel shader" )); + add2DBlitShaderToMap(GL_RED_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughR2DI, "Blit11 2D R I pixel shader" )); + + add3DBlitShaderToMap(GL_RGBA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D RGBA pixel shader" )); + add3DBlitShaderToMap(GL_RGBA_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DUI, "Blit11 3D UI RGBA pixel shader" )); + add3DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DI, "Blit11 3D I RGBA pixel shader" )); + add3DBlitShaderToMap(GL_BGRA_EXT, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D BGRA pixel shader" )); + add3DBlitShaderToMap(GL_RGB, false, d3d11::CompilePS(device, g_PS_PassthroughRGB3D, "Blit11 3D RGB pixel shader" )); + add3DBlitShaderToMap(GL_RGB_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGB3DUI, "Blit11 3D RGB UI pixel shader" )); + add3DBlitShaderToMap(GL_RGB_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGB3DI, "Blit11 3D RGB I pixel shader" )); + add3DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG3D, "Blit11 3D RG pixel shader" )); + add3DBlitShaderToMap(GL_RG_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRG3DUI, "Blit11 3D RG UI pixel shader" )); + add3DBlitShaderToMap(GL_RG_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRG3DI, "Blit11 3D RG I pixel shader" )); + add3DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR3D, "Blit11 3D R pixel shader" )); + add3DBlitShaderToMap(GL_RED_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughR3DUI, "Blit11 3D R UI pixel shader" )); + add3DBlitShaderToMap(GL_RED_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughR3DI, "Blit11 3D R I pixel shader" )); + add3DBlitShaderToMap(GL_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D alpha pixel shader" )); + add3DBlitShaderToMap(GL_LUMINANCE, false, d3d11::CompilePS(device, g_PS_PassthroughLum3D, "Blit11 3D luminance pixel shader" )); + add3DBlitShaderToMap(GL_LUMINANCE_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha3D, "Blit11 3D luminance alpha pixel shader")); + + addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleUI2D, "Blit11 2D UI swizzle pixel shader")); + addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleI2D, "Blit11 2D I swizzle pixel shader" )); + + addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleF2DArray, "Blit11 2D Cube F swizzle pixel shader" )); + addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleUI2DArray, "Blit11 2D Cube UI swizzle pixel shader")); + addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleI2DArray, "Blit11 2D Cube I swizzle pixel shader" )); + + addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleF3D, "Blit11 3D F swizzle pixel shader" )); + addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleUI3D, "Blit11 3D UI swizzle pixel shader")); + addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleI3D, "Blit11 3D I swizzle pixel shader" )); + + addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleF2DArray, "Blit11 2D Array F swizzle pixel shader" )); + addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleUI2DArray, "Blit11 2D Array UI swizzle pixel shader")); + addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleI2DArray, "Blit11 2D Array I swizzle pixel shader" )); +} + +void Blit11::clearShaderMap() +{ + for (BlitShaderMap::iterator i = mBlitShaderMap.begin(); i != mBlitShaderMap.end(); ++i) + { + Shader &shader = i->second; + SafeRelease(shader.mPixelShader); + } + mBlitShaderMap.clear(); + + for (SwizzleShaderMap::iterator i = mSwizzleShaderMap.begin(); i != mSwizzleShaderMap.end(); ++i) + { + Shader &shader = i->second; + SafeRelease(shader.mPixelShader); + } + mSwizzleShaderMap.clear(); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.h new file mode 100644 index 0000000000..fba89e20ba --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.h @@ -0,0 +1,126 @@ +// +// 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. +// + +// Blit11.cpp: Texture copy utility class. + +#ifndef LIBGLESV2_BLIT11_H_ +#define LIBGLESV2_BLIT11_H_ + +#include "common/angleutils.h" +#include "libGLESv2/angletypes.h" + +namespace rx +{ +class Renderer11; + +enum Filter +{ + Point, + Linear, +}; + +class Blit11 +{ + public: + explicit Blit11(Renderer11 *renderer); + ~Blit11(); + + bool swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderTargetView *dest, const gl::Extents &size, + GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); + + bool copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, GLenum destFormat, GLenum filter); + + bool copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor); + + bool copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor); + + bool copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor); + + private: + rx::Renderer11 *mRenderer; + + struct BlitParameters + { + GLenum mDestinationFormat; + bool mSignedInteger; + bool m3DBlit; + }; + + bool copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, bool stencilOnly); + + static bool compareBlitParameters(const BlitParameters &a, const BlitParameters &b); + + typedef void (*WriteVertexFunction)(const gl::Box &sourceArea, const gl::Extents &sourceSize, + const gl::Box &destArea, const gl::Extents &destSize, + void *outVertices, unsigned int *outStride, unsigned int *outVertexCount, + D3D11_PRIMITIVE_TOPOLOGY *outTopology); + + struct Shader + { + WriteVertexFunction mVertexWriteFunction; + ID3D11InputLayout *mInputLayout; + ID3D11VertexShader *mVertexShader; + ID3D11GeometryShader *mGeometryShader; + ID3D11PixelShader *mPixelShader; + }; + + typedef bool (*BlitParametersComparisonFunction)(const BlitParameters&, const BlitParameters &); + typedef std::map<BlitParameters, Shader, BlitParametersComparisonFunction> BlitShaderMap; + BlitShaderMap mBlitShaderMap; + + void add2DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps); + void add3DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps); + + struct SwizzleParameters + { + GLenum mDestinationType; + D3D11_SRV_DIMENSION mViewDimension; + }; + + static bool compareSwizzleParameters(const SwizzleParameters &a, const SwizzleParameters &b); + + typedef bool (*SwizzleParametersComparisonFunction)(const SwizzleParameters&, const SwizzleParameters &); + typedef std::map<SwizzleParameters, Shader, SwizzleParametersComparisonFunction> SwizzleShaderMap; + SwizzleShaderMap mSwizzleShaderMap; + + void addSwizzleShaderToMap(GLenum destType, D3D11_SRV_DIMENSION viewDimension, ID3D11PixelShader *ps); + + void buildShaderMap(); + void clearShaderMap(); + + ID3D11Buffer *mVertexBuffer; + ID3D11SamplerState *mPointSampler; + ID3D11SamplerState *mLinearSampler; + ID3D11RasterizerState *mScissorEnabledRasterizerState; + ID3D11RasterizerState *mScissorDisabledRasterizerState; + ID3D11DepthStencilState *mDepthStencilState; + + ID3D11InputLayout *mQuad2DIL; + ID3D11VertexShader *mQuad2DVS; + ID3D11PixelShader *mDepthPS; + + ID3D11InputLayout *mQuad3DIL; + ID3D11VertexShader *mQuad3DVS; + ID3D11GeometryShader *mQuad3DGS; + + ID3D11Buffer *mSwizzleCB; + + DISALLOW_COPY_AND_ASSIGN(Blit11); +}; + +} + +#endif // LIBGLESV2_BLIT11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp new file mode 100644 index 0000000000..1301124b2d --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp @@ -0,0 +1,904 @@ +#include "precompiled.h" +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Buffer11.cpp Defines the Buffer11 class. + +#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" +#include "libGLESv2/main.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" + +#if defined(__MINGW32__) && !defined(D3D11_MAP_FLAG_DO_NOT_WAIT) +# define D3D11_MAP_FLAG_DO_NOT_WAIT 0x100000L +#endif + +namespace rx +{ + +PackPixelsParams::PackPixelsParams() + : format(GL_NONE), + type(GL_NONE), + outputPitch(0), + packBuffer(NULL), + offset(0) +{} + +PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn, GLenum formatIn, GLenum typeIn, GLuint outputPitchIn, + const gl::PixelPackState &packIn, ptrdiff_t offsetIn) + : area(areaIn), + format(formatIn), + type(typeIn), + outputPitch(outputPitchIn), + packBuffer(packIn.pixelBuffer.get()), + pack(packIn.alignment, packIn.reverseRowOrder), + offset(offsetIn) +{} + +namespace gl_d3d11 +{ + +D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access) +{ + bool readBit = ((access & GL_MAP_READ_BIT) != 0); + bool writeBit = ((access & GL_MAP_WRITE_BIT) != 0); + + ASSERT(readBit || writeBit); + + // Note : we ignore the discard bit, because in D3D11, staging buffers + // don't accept the map-discard flag (discard only works for DYNAMIC usage) + + if (readBit && !writeBit) + { + return D3D11_MAP_READ; + } + else if (writeBit && !readBit) + { + return D3D11_MAP_WRITE; + } + else if (writeBit && readBit) + { + return D3D11_MAP_READ_WRITE; + } + else + { + UNREACHABLE(); + return D3D11_MAP_READ; + } +} + +} + +// Each instance of Buffer11::BufferStorage11 is specialized for a class of D3D binding points +// - vertex/transform feedback buffers +// - index buffers +// - pixel unpack buffers +// - uniform buffers +class Buffer11::BufferStorage11 +{ + public: + virtual ~BufferStorage11() {} + + DataRevision getDataRevision() const { return mRevision; } + BufferUsage getUsage() const { return mUsage; } + size_t getSize() const { return mBufferSize; } + bool isMappable() const { return (mUsage == BUFFER_USAGE_STAGING || mUsage == BUFFER_USAGE_PIXEL_PACK); } + + void setDataRevision(DataRevision rev) { mRevision = rev; } + + virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset, + size_t size, size_t destOffset) = 0; + virtual bool resize(size_t size, bool preserveData) = 0; + + virtual void *map(size_t offset, size_t length, GLbitfield access) = 0; + virtual void unmap() = 0; + + protected: + BufferStorage11(Renderer11 *renderer, BufferUsage usage); + + Renderer11 *mRenderer; + DataRevision mRevision; + const BufferUsage mUsage; + size_t mBufferSize; +}; + +// A native buffer storage represents an underlying D3D11 buffer for a particular +// type of storage. +class Buffer11::NativeBuffer11 : public Buffer11::BufferStorage11 +{ + public: + NativeBuffer11(Renderer11 *renderer, BufferUsage usage); + ~NativeBuffer11(); + + ID3D11Buffer *getNativeBuffer() const { return mNativeBuffer; } + + virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset, + size_t size, size_t destOffset); + virtual bool resize(size_t size, bool preserveData); + + virtual void *map(size_t offset, size_t length, GLbitfield access); + virtual void unmap(); + + private: + ID3D11Buffer *mNativeBuffer; + + static void fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer *renderer, BufferUsage usage, unsigned int bufferSize); +}; + +// Pack storage represents internal storage for pack buffers. We implement pack buffers +// as CPU memory, tied to a staging texture, for asynchronous texture readback. +class Buffer11::PackStorage11 : public Buffer11::BufferStorage11 +{ + public: + PackStorage11(Renderer11 *renderer); + ~PackStorage11(); + + virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset, + size_t size, size_t destOffset); + virtual bool resize(size_t size, bool preserveData); + + virtual void *map(size_t offset, size_t length, GLbitfield access); + virtual void unmap(); + + void packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms); + + private: + + void flushQueuedPackCommand(); + + ID3D11Texture2D *mStagingTexture; + DXGI_FORMAT mTextureFormat; + gl::Extents mTextureSize; + MemoryBuffer mMemoryBuffer; + PackPixelsParams *mQueuedPackCommand; + PackPixelsParams mPackParams; + bool mDataModified; +}; + + +Buffer11::Buffer11(Renderer11 *renderer) + : BufferD3D(), + mRenderer(renderer), + mSize(0), + mMappedStorage(NULL), + mResolvedDataRevision(0), + mReadUsageCount(0) +{ +} + +Buffer11::~Buffer11() +{ + clear(); +} + +Buffer11 *Buffer11::makeBuffer11(BufferImpl *buffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(Buffer11*, buffer)); + return static_cast<Buffer11*>(buffer); +} + +void Buffer11::clear() +{ + for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++) + { + SafeDelete(it->second); + } + + mBufferStorages.clear(); + + mSize = 0; + mResolvedDataRevision = 0; +} + +void Buffer11::setData(const void* data, size_t size, GLenum usage) +{ + mIndexRangeCache.clear(); + + setSubData(data, size, 0); + + if (usage == GL_STATIC_DRAW) + { + initializeStaticData(); + } +} + +void *Buffer11::getData() +{ + NativeBuffer11 *stagingBuffer = getStagingBuffer(); + + if (!stagingBuffer) + { + // Out-of-memory + return NULL; + } + + if (stagingBuffer->getDataRevision() > mResolvedDataRevision) + { + if (stagingBuffer->getSize() > mResolvedData.size()) + { + if (!mResolvedData.resize(stagingBuffer->getSize())) + { + return gl::error(GL_OUT_OF_MEMORY, (void*)NULL); + } + } + + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = context->Map(stagingBuffer->getNativeBuffer(), 0, D3D11_MAP_READ, 0, &mappedResource); + if (FAILED(result)) + { + return gl::error(GL_OUT_OF_MEMORY, (void*)NULL); + } + + memcpy(mResolvedData.data(), mappedResource.pData, stagingBuffer->getSize()); + + context->Unmap(stagingBuffer->getNativeBuffer(), 0); + + mResolvedDataRevision = stagingBuffer->getDataRevision(); + } + + mReadUsageCount = 0; + + return mResolvedData.data(); +} + +void Buffer11::setSubData(const void* data, size_t size, size_t offset) +{ + size_t requiredSize = size + offset; + mSize = std::max(mSize, requiredSize); + + mIndexRangeCache.invalidateRange(offset, size); + invalidateStaticData(); + + if (data && size > 0) + { + NativeBuffer11 *stagingBuffer = getStagingBuffer(); + + if (!stagingBuffer) + { + // Out-of-memory + return; + } + + // Explicitly resize the staging buffer, preserving data if the new data will not + // completely fill the buffer + if (stagingBuffer->getSize() < requiredSize) + { + bool preserveData = (offset > 0); + if (!stagingBuffer->resize(requiredSize, preserveData)) + { + // Out-of-memory + return; + } + } + + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = context->Map(stagingBuffer->getNativeBuffer(), 0, D3D11_MAP_WRITE, 0, &mappedResource); + if (FAILED(result)) + { + return gl::error(GL_OUT_OF_MEMORY); + } + + unsigned char *offsetBufferPointer = reinterpret_cast<unsigned char *>(mappedResource.pData) + offset; + memcpy(offsetBufferPointer, data, size); + + context->Unmap(stagingBuffer->getNativeBuffer(), 0); + + stagingBuffer->setDataRevision(stagingBuffer->getDataRevision() + 1); + } +} + +void Buffer11::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) +{ + Buffer11 *sourceBuffer = makeBuffer11(source); + if (sourceBuffer) + { + BufferStorage11 *dest = getLatestBufferStorage(); + if (!dest) + { + dest = getStagingBuffer(); + } + + BufferStorage11 *source = sourceBuffer->getLatestBufferStorage(); + if (source && dest) + { + // If copying to/from a pixel pack buffer, we must have a staging or + // pack buffer partner, because other native buffers can't be mapped + if (dest->getUsage() == BUFFER_USAGE_PIXEL_PACK && !source->isMappable()) + { + source = sourceBuffer->getStagingBuffer(); + } + else if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK && !dest->isMappable()) + { + dest = getStagingBuffer(); + } + + dest->copyFromStorage(source, sourceOffset, size, destOffset); + dest->setDataRevision(dest->getDataRevision() + 1); + } + + mSize = std::max<size_t>(mSize, destOffset + size); + } + + invalidateStaticData(); +} + +GLvoid *Buffer11::map(size_t offset, size_t length, GLbitfield access) +{ + ASSERT(!mMappedStorage); + + BufferStorage11 *latestStorage = getLatestBufferStorage(); + if (latestStorage && + (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK || + latestStorage->getUsage() == BUFFER_USAGE_STAGING)) + { + // Latest storage is mappable. + mMappedStorage = latestStorage; + } + else + { + // Fall back to using the staging buffer if the latest storage does + // not exist or is not CPU-accessible. + mMappedStorage = getStagingBuffer(); + } + + if (!mMappedStorage) + { + // Out-of-memory + return NULL; + } + + if ((access & GL_MAP_WRITE_BIT) > 0) + { + // Update the data revision immediately, since the data might be changed at any time + mMappedStorage->setDataRevision(mMappedStorage->getDataRevision() + 1); + } + + return mMappedStorage->map(offset, length, access); +} + +void Buffer11::unmap() +{ + ASSERT(mMappedStorage); + mMappedStorage->unmap(); + mMappedStorage = NULL; +} + +void Buffer11::markTransformFeedbackUsage() +{ + BufferStorage11 *transformFeedbackStorage = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + + if (transformFeedbackStorage) + { + transformFeedbackStorage->setDataRevision(transformFeedbackStorage->getDataRevision() + 1); + } + + invalidateStaticData(); +} + +void Buffer11::markBufferUsage() +{ + mReadUsageCount++; + + const unsigned int usageLimit = 5; + + if (mReadUsageCount > usageLimit && mResolvedData.size() > 0) + { + mResolvedData.resize(0); + mResolvedDataRevision = 0; + } +} + +Renderer* Buffer11::getRenderer() +{ + return mRenderer; +} + +ID3D11Buffer *Buffer11::getBuffer(BufferUsage usage) +{ + markBufferUsage(); + + BufferStorage11 *bufferStorage = getBufferStorage(usage); + + if (!bufferStorage) + { + // Storage out-of-memory + return NULL; + } + + ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, bufferStorage)); + + return static_cast<NativeBuffer11*>(bufferStorage)->getNativeBuffer(); +} + +ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat) +{ + BufferStorage11 *storage = getBufferStorage(BUFFER_USAGE_PIXEL_UNPACK); + + if (!storage) + { + // Storage out-of-memory + return NULL; + } + + ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, storage)); + ID3D11Buffer *buffer = static_cast<NativeBuffer11*>(storage)->getNativeBuffer(); + + auto bufferSRVIt = mBufferResourceViews.find(srvFormat); + + if (bufferSRVIt != mBufferResourceViews.end()) + { + if (bufferSRVIt->second.first == buffer) + { + return bufferSRVIt->second.second; + } + else + { + // The underlying buffer has changed since the SRV was created: recreate the SRV. + SafeRelease(bufferSRVIt->second.second); + } + } + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11ShaderResourceView *bufferSRV = NULL; + + D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc; + bufferSRVDesc.Buffer.ElementOffset = 0; + bufferSRVDesc.Buffer.ElementWidth = mSize / d3d11::GetFormatPixelBytes(srvFormat); + bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + bufferSRVDesc.Format = srvFormat; + + HRESULT result = device->CreateShaderResourceView(buffer, &bufferSRVDesc, &bufferSRV); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + mBufferResourceViews[srvFormat] = BufferSRVPair(buffer, bufferSRV); + + return bufferSRV; +} + +void Buffer11::packPixels(ID3D11Texture2D *srcTexture, UINT srcSubresource, const PackPixelsParams ¶ms) +{ + PackStorage11 *packStorage = getPackStorage(); + + BufferStorage11 *latestStorage = getLatestBufferStorage(); + + if (packStorage) + { + packStorage->packPixels(srcTexture, srcSubresource, params); + packStorage->setDataRevision(latestStorage ? latestStorage->getDataRevision() + 1 : 1); + } +} + +Buffer11::BufferStorage11 *Buffer11::getBufferStorage(BufferUsage usage) +{ + BufferStorage11 *directBuffer = NULL; + auto directBufferIt = mBufferStorages.find(usage); + if (directBufferIt != mBufferStorages.end()) + { + directBuffer = directBufferIt->second; + } + + if (!directBuffer) + { + if (usage == BUFFER_USAGE_PIXEL_PACK) + { + directBuffer = new PackStorage11(mRenderer); + } + else + { + // buffer is not allocated, create it + directBuffer = new NativeBuffer11(mRenderer, usage); + } + + mBufferStorages.insert(std::make_pair(usage, directBuffer)); + } + + // resize buffer + if (directBuffer->getSize() < mSize) + { + if (!directBuffer->resize(mSize, true)) + { + // Out of memory error + return NULL; + } + } + + BufferStorage11 *latestBuffer = getLatestBufferStorage(); + if (latestBuffer && latestBuffer->getDataRevision() > directBuffer->getDataRevision()) + { + // if copying from a pack buffer to a non-staging native buffer, we must first + // copy through the staging buffer, because other native buffers can't be mapped + if (latestBuffer->getUsage() == BUFFER_USAGE_PIXEL_PACK && !directBuffer->isMappable()) + { + NativeBuffer11 *stagingBuffer = getStagingBuffer(); + + stagingBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0); + directBuffer->setDataRevision(latestBuffer->getDataRevision()); + + latestBuffer = stagingBuffer; + } + + // if copyFromStorage returns true, the D3D buffer has been recreated + // and we should update our serial + if (directBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0)) + { + updateSerial(); + } + directBuffer->setDataRevision(latestBuffer->getDataRevision()); + } + + return directBuffer; +} + +Buffer11::BufferStorage11 *Buffer11::getLatestBufferStorage() const +{ + // Even though we iterate over all the direct buffers, it is expected that only + // 1 or 2 will be present. + BufferStorage11 *latestStorage = NULL; + DataRevision latestRevision = 0; + for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++) + { + BufferStorage11 *storage = it->second; + if (!latestStorage || storage->getDataRevision() > latestRevision) + { + latestStorage = storage; + latestRevision = storage->getDataRevision(); + } + } + + return latestStorage; +} + +Buffer11::NativeBuffer11 *Buffer11::getStagingBuffer() +{ + BufferStorage11 *stagingStorage = getBufferStorage(BUFFER_USAGE_STAGING); + + if (!stagingStorage) + { + // Out-of-memory + return NULL; + } + + ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, stagingStorage)); + return static_cast<NativeBuffer11*>(stagingStorage); +} + +Buffer11::PackStorage11 *Buffer11::getPackStorage() +{ + BufferStorage11 *packStorage = getBufferStorage(BUFFER_USAGE_PIXEL_PACK); + + if (!packStorage) + { + // Out-of-memory + return NULL; + } + + ASSERT(HAS_DYNAMIC_TYPE(PackStorage11*, packStorage)); + return static_cast<PackStorage11*>(packStorage); +} + +Buffer11::BufferStorage11::BufferStorage11(Renderer11 *renderer, BufferUsage usage) + : mRenderer(renderer), + mUsage(usage), + mRevision(0), + mBufferSize(0) +{ +} + +Buffer11::NativeBuffer11::NativeBuffer11(Renderer11 *renderer, BufferUsage usage) + : BufferStorage11(renderer, usage), + mNativeBuffer(NULL) +{ +} + +Buffer11::NativeBuffer11::~NativeBuffer11() +{ + SafeRelease(mNativeBuffer); +} + +// Returns true if it recreates the direct buffer +bool Buffer11::NativeBuffer11::copyFromStorage(BufferStorage11 *source, size_t sourceOffset, + size_t size, size_t destOffset) +{ + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + size_t requiredSize = sourceOffset + size; + bool createBuffer = !mNativeBuffer || mBufferSize < requiredSize; + + // (Re)initialize D3D buffer if needed + if (createBuffer) + { + bool preserveData = (destOffset > 0); + resize(source->getSize(), preserveData); + } + + if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK) + { + ASSERT(HAS_DYNAMIC_TYPE(PackStorage11*, source)); + + void *sourcePointer = source->map(sourceOffset, size, GL_MAP_READ_BIT); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT hr = context->Map(mNativeBuffer, 0, D3D11_MAP_WRITE, 0, &mappedResource); + UNUSED_ASSERTION_VARIABLE(hr); + ASSERT(SUCCEEDED(hr)); + + unsigned char *destPointer = static_cast<unsigned char *>(mappedResource.pData) + destOffset; + + // Offset bounds are validated at the API layer + ASSERT(sourceOffset + size <= destOffset + mBufferSize); + memcpy(destPointer, sourcePointer, size); + } + else + { + ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, source)); + + D3D11_BOX srcBox; + srcBox.left = sourceOffset; + srcBox.right = sourceOffset + size; + srcBox.top = 0; + srcBox.bottom = 1; + srcBox.front = 0; + srcBox.back = 1; + + ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, source)); + ID3D11Buffer *sourceBuffer = static_cast<NativeBuffer11*>(source)->getNativeBuffer(); + + context->CopySubresourceRegion(mNativeBuffer, 0, destOffset, 0, 0, sourceBuffer, 0, &srcBox); + } + + return createBuffer; +} + +bool Buffer11::NativeBuffer11::resize(size_t size, bool preserveData) +{ + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + D3D11_BUFFER_DESC bufferDesc; + fillBufferDesc(&bufferDesc, mRenderer, mUsage, size); + + ID3D11Buffer *newBuffer; + HRESULT result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer); + + if (FAILED(result)) + { + return gl::error(GL_OUT_OF_MEMORY, false); + } + + if (mNativeBuffer && preserveData) + { + // We don't call resize if the buffer is big enough already. + ASSERT(mBufferSize <= size); + + D3D11_BOX srcBox; + srcBox.left = 0; + srcBox.right = mBufferSize; + srcBox.top = 0; + srcBox.bottom = 1; + srcBox.front = 0; + srcBox.back = 1; + + context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mNativeBuffer, 0, &srcBox); + } + + // No longer need the old buffer + SafeRelease(mNativeBuffer); + mNativeBuffer = newBuffer; + + mBufferSize = bufferDesc.ByteWidth; + + return true; +} + +void Buffer11::NativeBuffer11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer *renderer, + BufferUsage usage, unsigned int bufferSize) +{ + bufferDesc->ByteWidth = bufferSize; + bufferDesc->MiscFlags = 0; + bufferDesc->StructureByteStride = 0; + + switch (usage) + { + case BUFFER_USAGE_STAGING: + bufferDesc->Usage = D3D11_USAGE_STAGING; + bufferDesc->BindFlags = 0; + bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + break; + + case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK: + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER; + if (renderer->getMaxTransformFeedbackBuffers() > 0) + bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT; + bufferDesc->CPUAccessFlags = 0; + break; + + case BUFFER_USAGE_INDEX: + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER; + bufferDesc->CPUAccessFlags = 0; + break; + + case BUFFER_USAGE_PIXEL_UNPACK: + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE; + bufferDesc->CPUAccessFlags = 0; + break; + + case BUFFER_USAGE_UNIFORM: + bufferDesc->Usage = D3D11_USAGE_DYNAMIC; + bufferDesc->BindFlags = D3D11_BIND_CONSTANT_BUFFER; + bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + + // Constant buffers must be of a limited size, and aligned to 16 byte boundaries + // For our purposes we ignore any buffer data past the maximum constant buffer size + bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u); + bufferDesc->ByteWidth = std::min(bufferDesc->ByteWidth, renderer->getMaxUniformBufferSize()); + break; + + default: + UNREACHABLE(); + } +} + +void *Buffer11::NativeBuffer11::map(size_t offset, size_t length, GLbitfield access) +{ + ASSERT(mUsage == BUFFER_USAGE_STAGING); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + D3D11_MAP d3dMapType = gl_d3d11::GetD3DMapTypeFromBits(access); + UINT d3dMapFlag = ((access & GL_MAP_UNSYNCHRONIZED_BIT) != 0 ? D3D11_MAP_FLAG_DO_NOT_WAIT : 0); + + HRESULT result = context->Map(mNativeBuffer, 0, d3dMapType, d3dMapFlag, &mappedResource); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + return static_cast<GLubyte*>(mappedResource.pData) + offset; +} + +void Buffer11::NativeBuffer11::unmap() +{ + ASSERT(mUsage == BUFFER_USAGE_STAGING); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + context->Unmap(mNativeBuffer, 0); +} + +Buffer11::PackStorage11::PackStorage11(Renderer11 *renderer) + : BufferStorage11(renderer, BUFFER_USAGE_PIXEL_PACK), + mStagingTexture(NULL), + mTextureFormat(DXGI_FORMAT_UNKNOWN), + mQueuedPackCommand(NULL), + mDataModified(false) +{ +} + +Buffer11::PackStorage11::~PackStorage11() +{ + SafeRelease(mStagingTexture); + SafeDelete(mQueuedPackCommand); +} + +bool Buffer11::PackStorage11::copyFromStorage(BufferStorage11 *source, size_t sourceOffset, + size_t size, size_t destOffset) +{ + UNIMPLEMENTED(); + return false; +} + +bool Buffer11::PackStorage11::resize(size_t size, bool preserveData) +{ + if (size != mBufferSize) + { + if (!mMemoryBuffer.resize(size)) + { + return false; + } + mBufferSize = size; + } + + return true; +} + +void *Buffer11::PackStorage11::map(size_t offset, size_t length, GLbitfield access) +{ + ASSERT(offset + length <= getSize()); + // TODO: fast path + // We might be able to optimize out one or more memcpy calls by detecting when + // and if D3D packs the staging texture memory identically to how we would fill + // the pack buffer according to the current pack state. + + flushQueuedPackCommand(); + mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0); + + return mMemoryBuffer.data() + offset; +} + +void Buffer11::PackStorage11::unmap() +{ + // No-op +} + +void Buffer11::PackStorage11::packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms) +{ + flushQueuedPackCommand(); + mQueuedPackCommand = new PackPixelsParams(params); + + D3D11_TEXTURE2D_DESC textureDesc; + srcTexure->GetDesc(&textureDesc); + + if (mStagingTexture != NULL && + (mTextureFormat != textureDesc.Format || + mTextureSize.width != params.area.width || + mTextureSize.height != params.area.height)) + { + SafeRelease(mStagingTexture); + mTextureSize.width = 0; + mTextureSize.height = 0; + mTextureFormat = DXGI_FORMAT_UNKNOWN; + } + + if (mStagingTexture == NULL) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT hr; + + mTextureSize.width = params.area.width; + mTextureSize.height = params.area.height; + mTextureFormat = textureDesc.Format; + + D3D11_TEXTURE2D_DESC stagingDesc; + stagingDesc.Width = params.area.width; + stagingDesc.Height = params.area.height; + stagingDesc.MipLevels = 1; + stagingDesc.ArraySize = 1; + stagingDesc.Format = mTextureFormat; + stagingDesc.SampleDesc.Count = 1; + stagingDesc.SampleDesc.Quality = 0; + stagingDesc.Usage = D3D11_USAGE_STAGING; + stagingDesc.BindFlags = 0; + stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + stagingDesc.MiscFlags = 0; + + hr = device->CreateTexture2D(&stagingDesc, NULL, &mStagingTexture); + ASSERT(SUCCEEDED(hr)); + } + + if (textureDesc.SampleDesc.Count > 1) + { + UNIMPLEMENTED(); + } + + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + D3D11_BOX srcBox; + srcBox.left = params.area.x; + srcBox.right = params.area.x + params.area.width; + srcBox.top = params.area.y; + srcBox.bottom = params.area.y + params.area.height; + srcBox.front = 0; + srcBox.back = 1; + + // Asynchronous copy + immediateContext->CopySubresourceRegion(mStagingTexture, 0, 0, 0, 0, srcTexure, srcSubresource, &srcBox); +} + +void Buffer11::PackStorage11::flushQueuedPackCommand() +{ + ASSERT(mMemoryBuffer.size() > 0); + + if (mQueuedPackCommand) + { + mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data()); + SafeDelete(mQueuedPackCommand); + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.h new file mode 100644 index 0000000000..e56be247c4 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.h @@ -0,0 +1,106 @@ +// +// 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. +// + +// Buffer11.h: Defines the rx::Buffer11 class which implements rx::BufferImpl via rx::BufferD3D. + +#ifndef LIBGLESV2_RENDERER_BUFFER11_H_ +#define LIBGLESV2_RENDERER_BUFFER11_H_ + +#include "libGLESv2/renderer/d3d/BufferD3D.h" +#include "libGLESv2/renderer/d3d/MemoryBuffer.h" +#include "libGLESv2/angletypes.h" + +namespace rx +{ +class Renderer11; + +enum BufferUsage +{ + BUFFER_USAGE_STAGING, + BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK, + BUFFER_USAGE_INDEX, + BUFFER_USAGE_PIXEL_UNPACK, + BUFFER_USAGE_PIXEL_PACK, + BUFFER_USAGE_UNIFORM, +}; + +struct PackPixelsParams +{ + PackPixelsParams(); + PackPixelsParams(const gl::Rectangle &area, GLenum format, GLenum type, GLuint outputPitch, + const gl::PixelPackState &pack, ptrdiff_t offset); + + gl::Rectangle area; + GLenum format; + GLenum type; + GLuint outputPitch; + gl::Buffer *packBuffer; + gl::PixelPackState pack; + ptrdiff_t offset; +}; + +typedef size_t DataRevision; + +class Buffer11 : public BufferD3D +{ + public: + Buffer11(rx::Renderer11 *renderer); + virtual ~Buffer11(); + + static Buffer11 *makeBuffer11(BufferImpl *buffer); + + ID3D11Buffer *getBuffer(BufferUsage usage); + ID3D11ShaderResourceView *getSRV(DXGI_FORMAT srvFormat); + bool isMapped() const { return mMappedStorage != NULL; } + void packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms); + + // BufferD3D implementation + virtual size_t getSize() const { return mSize; } + virtual void clear(); + virtual bool supportsDirectBinding() const { return true; } + virtual Renderer* getRenderer(); + + // BufferImpl implementation + virtual void setData(const void* data, size_t size, GLenum usage); + virtual void *getData(); + virtual void setSubData(const void* data, size_t size, size_t offset); + virtual void copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); + virtual GLvoid* map(size_t offset, size_t length, GLbitfield access); + virtual void unmap(); + virtual void markTransformFeedbackUsage(); + + private: + DISALLOW_COPY_AND_ASSIGN(Buffer11); + + class BufferStorage11; + class NativeBuffer11; + class PackStorage11; + + rx::Renderer11 *mRenderer; + size_t mSize; + + BufferStorage11 *mMappedStorage; + + std::map<BufferUsage, BufferStorage11*> mBufferStorages; + + typedef std::pair<ID3D11Buffer *, ID3D11ShaderResourceView *> BufferSRVPair; + std::map<DXGI_FORMAT, BufferSRVPair> mBufferResourceViews; + + MemoryBuffer mResolvedData; + DataRevision mResolvedDataRevision; + unsigned int mReadUsageCount; + + void markBufferUsage(); + NativeBuffer11 *getStagingBuffer(); + PackStorage11 *getPackStorage(); + + BufferStorage11 *getBufferStorage(BufferUsage usage); + BufferStorage11 *getLatestBufferStorage() const; +}; + +} + +#endif // LIBGLESV2_RENDERER_BUFFER11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp new file mode 100644 index 0000000000..5121950da0 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp @@ -0,0 +1,568 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Clear11.cpp: Framebuffer clear utility class. + +#include "libGLESv2/renderer/d3d/d3d11/Clear11.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" + +#include "libGLESv2/formatutils.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" + +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearfloatvs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearfloatps.h" + +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearuintvs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearuintps.h" + +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearsintvs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearsintps.h" + +namespace rx +{ + +template <typename T> +static void ApplyVertices(const gl::Extents &framebufferSize, const gl::Rectangle *scissor, const gl::Color<T> &color, float depth, void *buffer) +{ + d3d11::PositionDepthColorVertex<T> *vertices = reinterpret_cast<d3d11::PositionDepthColorVertex<T>*>(buffer); + + float depthClear = gl::clamp01(depth); + float left = -1.0f; + float right = 1.0f; + float top = -1.0f; + float bottom = 1.0f; + + // Clip the quad coordinates to the scissor if needed + if (scissor != NULL) + { + left = std::max(left, (scissor->x / float(framebufferSize.width)) * 2.0f - 1.0f); + right = std::min(right, ((scissor->x + scissor->width) / float(framebufferSize.width)) * 2.0f - 1.0f); + top = std::max(top, ((framebufferSize.height - scissor->y - scissor->height) / float(framebufferSize.height)) * 2.0f - 1.0f); + bottom = std::min(bottom, ((framebufferSize.height - scissor->y) / float(framebufferSize.height)) * 2.0f - 1.0f); + } + + d3d11::SetPositionDepthColorVertex<T>(vertices + 0, left, bottom, depthClear, color); + d3d11::SetPositionDepthColorVertex<T>(vertices + 1, left, top, depthClear, color); + d3d11::SetPositionDepthColorVertex<T>(vertices + 2, right, bottom, depthClear, color); + d3d11::SetPositionDepthColorVertex<T>(vertices + 3, right, top, depthClear, color); +} + +template <unsigned int vsSize, unsigned int psSize> +Clear11::ClearShader Clear11::CreateClearShader(ID3D11Device *device, DXGI_FORMAT colorType, const BYTE (&vsByteCode)[vsSize], const BYTE (&psByteCode)[psSize]) +{ + HRESULT result; + + ClearShader shader = { 0 }; + + D3D11_INPUT_ELEMENT_DESC quadLayout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, colorType, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + result = device->CreateInputLayout(quadLayout, ArraySize(quadLayout), vsByteCode, vsSize, &shader.inputLayout); + ASSERT(SUCCEEDED(result)); + + result = device->CreateVertexShader(vsByteCode, vsSize, NULL, &shader.vertexShader); + ASSERT(SUCCEEDED(result)); + + result = device->CreatePixelShader(psByteCode, psSize, NULL, &shader.pixelShader); + ASSERT(SUCCEEDED(result)); + + return shader; +} + +Clear11::Clear11(Renderer11 *renderer) + : mRenderer(renderer), mClearBlendStates(StructLessThan<ClearBlendInfo>), mClearDepthStencilStates(StructLessThan<ClearDepthStencilInfo>), + mVertexBuffer(NULL), mRasterizerState(NULL) +{ + HRESULT result; + ID3D11Device *device = renderer->getDevice(); + + D3D11_BUFFER_DESC vbDesc; + vbDesc.ByteWidth = sizeof(d3d11::PositionDepthColorVertex<float>) * 4; + vbDesc.Usage = D3D11_USAGE_DYNAMIC; + vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + vbDesc.MiscFlags = 0; + vbDesc.StructureByteStride = 0; + + result = device->CreateBuffer(&vbDesc, NULL, &mVertexBuffer); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mVertexBuffer, "Clear11 masked clear vertex buffer"); + + D3D11_RASTERIZER_DESC rsDesc; + rsDesc.FillMode = D3D11_FILL_SOLID; + rsDesc.CullMode = D3D11_CULL_NONE; + rsDesc.FrontCounterClockwise = FALSE; + rsDesc.DepthBias = 0; + rsDesc.DepthBiasClamp = 0.0f; + rsDesc.SlopeScaledDepthBias = 0.0f; + rsDesc.DepthClipEnable = mRenderer->isLevel9(); + rsDesc.ScissorEnable = FALSE; + rsDesc.MultisampleEnable = FALSE; + rsDesc.AntialiasedLineEnable = FALSE; + + result = device->CreateRasterizerState(&rsDesc, &mRasterizerState); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mRasterizerState, "Clear11 masked clear rasterizer state"); + + mFloatClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_FLOAT, g_VS_ClearFloat, g_PS_ClearFloat); + if (mRenderer->isLevel9()) { + memset(&mUintClearShader, 0, sizeof(ClearShader)); + memset(&mIntClearShader, 0, sizeof(ClearShader)); + return; + } + + mUintClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_UINT, g_VS_ClearUint, g_PS_ClearUint ); + mIntClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_SINT, g_VS_ClearSint, g_PS_ClearSint ); +} + +Clear11::~Clear11() +{ + for (ClearBlendStateMap::iterator i = mClearBlendStates.begin(); i != mClearBlendStates.end(); i++) + { + SafeRelease(i->second); + } + mClearBlendStates.clear(); + + SafeRelease(mFloatClearShader.inputLayout); + SafeRelease(mFloatClearShader.vertexShader); + SafeRelease(mFloatClearShader.pixelShader); + + SafeRelease(mUintClearShader.inputLayout); + SafeRelease(mUintClearShader.vertexShader); + SafeRelease(mUintClearShader.pixelShader); + + SafeRelease(mIntClearShader.inputLayout); + SafeRelease(mIntClearShader.vertexShader); + SafeRelease(mIntClearShader.pixelShader); + + for (ClearDepthStencilStateMap::iterator i = mClearDepthStencilStates.begin(); i != mClearDepthStencilStates.end(); i++) + { + SafeRelease(i->second); + } + mClearDepthStencilStates.clear(); + + SafeRelease(mVertexBuffer); + SafeRelease(mRasterizerState); +} + +void Clear11::clearFramebuffer(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) +{ + // First determine if a scissored clear is needed, this will always require drawing a quad. + // + // Otherwise, iterate over the color buffers which require clearing and determine if they can be + // cleared with ID3D11DeviceContext::ClearRenderTargetView... This requires: + // 1) The render target is being cleared to a float value (will be cast to integer when clearing integer + // render targets as expected but does not work the other way around) + // 2) The format of the render target has no color channels that are currently masked out. + // Clear the easy-to-clear buffers on the spot and accumulate the ones that require special work. + // + // Also determine if the depth stencil can be cleared with ID3D11DeviceContext::ClearDepthStencilView + // by checking if the stencil write mask covers the entire stencil. + // + // To clear the remaining buffers, quads must be drawn containing an int, uint or float vertex color + // attribute. + + gl::Extents framebufferSize; + if (frameBuffer->getFirstColorbuffer() != NULL) + { + gl::FramebufferAttachment *attachment = frameBuffer->getFirstColorbuffer(); + framebufferSize.width = attachment->getWidth(); + framebufferSize.height = attachment->getHeight(); + framebufferSize.depth = 1; + } + else if (frameBuffer->getDepthOrStencilbuffer() != NULL) + { + gl::FramebufferAttachment *attachment = frameBuffer->getDepthOrStencilbuffer(); + framebufferSize.width = attachment->getWidth(); + framebufferSize.height = attachment->getHeight(); + framebufferSize.depth = 1; + } + else + { + UNREACHABLE(); + return; + } + + if (clearParams.scissorEnabled && (clearParams.scissor.x >= framebufferSize.width || + clearParams.scissor.y >= framebufferSize.height || + clearParams.scissor.x + clearParams.scissor.width <= 0 || + clearParams.scissor.y + clearParams.scissor.height <= 0)) + { + // Scissor is enabled and the scissor rectangle is outside the renderbuffer + return; + } + + bool needScissoredClear = clearParams.scissorEnabled && (clearParams.scissor.x > 0 || clearParams.scissor.y > 0 || + clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width || + clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height); + + std::vector<MaskedRenderTarget> maskedClearRenderTargets; + RenderTarget11* maskedClearDepthStencil = NULL; + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) + { + if (clearParams.clearColor[colorAttachment] && frameBuffer->isEnabledColorAttachment(colorAttachment)) + { + gl::FramebufferAttachment *attachment = frameBuffer->getColorbuffer(colorAttachment); + if (attachment) + { + RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(attachment->getRenderTarget()); + if (!renderTarget) + { + ERR("Render target pointer unexpectedly null."); + return; + } + + GLenum internalFormat = attachment->getInternalFormat(); + GLenum actualFormat = attachment->getActualFormat(); + GLenum componentType = gl::GetComponentType(internalFormat); + if (clearParams.colorClearType == GL_FLOAT && + !(componentType == GL_FLOAT || componentType == GL_UNSIGNED_NORMALIZED || componentType == GL_SIGNED_NORMALIZED)) + { + ERR("It is undefined behaviour to clear a render buffer which is not normalized fixed point or floating-" + "point to floating point values (color attachment %u has internal format 0x%X).", colorAttachment, internalFormat); + } + + GLuint internalRedBits = gl::GetRedBits(internalFormat); + GLuint internalGreenBits = gl::GetGreenBits(internalFormat); + GLuint internalBlueBits = gl::GetBlueBits(internalFormat); + GLuint internalAlphaBits = gl::GetAlphaBits(internalFormat); + + if ((internalRedBits == 0 || !clearParams.colorMaskRed) && + (internalGreenBits == 0 || !clearParams.colorMaskGreen) && + (internalBlueBits == 0 || !clearParams.colorMaskBlue) && + (internalAlphaBits == 0 || !clearParams.colorMaskAlpha)) + { + // Every channel either does not exist in the render target or is masked out + continue; + } + else if (needScissoredClear || clearParams.colorClearType != GL_FLOAT || + (internalRedBits > 0 && !clearParams.colorMaskRed) || + (internalGreenBits > 0 && !clearParams.colorMaskGreen) || + (internalBlueBits > 0 && !clearParams.colorMaskBlue) || + (internalAlphaBits > 0 && !clearParams.colorMaskAlpha)) + { + // A scissored or masked clear is required + MaskedRenderTarget maskAndRt; + bool clearColor = clearParams.clearColor[colorAttachment]; + maskAndRt.colorMask[0] = (clearColor && clearParams.colorMaskRed); + maskAndRt.colorMask[1] = (clearColor && clearParams.colorMaskGreen); + maskAndRt.colorMask[2] = (clearColor && clearParams.colorMaskBlue); + maskAndRt.colorMask[3] = (clearColor && clearParams.colorMaskAlpha); + maskAndRt.renderTarget = renderTarget; + maskedClearRenderTargets.push_back(maskAndRt); + } + else + { + // ID3D11DeviceContext::ClearRenderTargetView is possible + + ID3D11RenderTargetView *framebufferRTV = renderTarget->getRenderTargetView(); + if (!framebufferRTV) + { + ERR("Render target view pointer unexpectedly null."); + return; + } + + // Check if the actual format has a channel that the internal format does not and set them to the + // default values + GLuint actualRedBits = gl::GetRedBits(actualFormat); + GLuint actualGreenBits = gl::GetGreenBits(actualFormat); + GLuint actualBlueBits = gl::GetBlueBits(actualFormat); + GLuint actualAlphaBits = gl::GetAlphaBits(actualFormat); + + const float clearValues[4] = + { + ((internalRedBits == 0 && actualRedBits > 0) ? 0.0f : clearParams.colorFClearValue.red), + ((internalGreenBits == 0 && actualGreenBits > 0) ? 0.0f : clearParams.colorFClearValue.green), + ((internalBlueBits == 0 && actualBlueBits > 0) ? 0.0f : clearParams.colorFClearValue.blue), + ((internalAlphaBits == 0 && actualAlphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha), + }; + + deviceContext->ClearRenderTargetView(framebufferRTV, clearValues); + } + } + } + } + + if (clearParams.clearDepth || clearParams.clearStencil) + { + gl::FramebufferAttachment *attachment = frameBuffer->getDepthOrStencilbuffer(); + if (attachment) + { + RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(attachment->getDepthStencil()); + if (!renderTarget) + { + ERR("Depth stencil render target pointer unexpectedly null."); + return; + } + + GLenum actualFormat = attachment->getActualFormat(); + + unsigned int stencilUnmasked = frameBuffer->hasStencil() ? (1 << gl::GetStencilBits(actualFormat)) - 1 : 0; + bool needMaskedStencilClear = clearParams.clearStencil && (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; + + if (needScissoredClear || needMaskedStencilClear) + { + maskedClearDepthStencil = renderTarget; + } + else + { + ID3D11DepthStencilView *framebufferDSV = renderTarget->getDepthStencilView(); + if (!framebufferDSV) + { + ERR("Depth stencil view pointer unexpectedly null."); + return; + } + + UINT clearFlags = (clearParams.clearDepth ? D3D11_CLEAR_DEPTH : 0) | + (clearParams.clearStencil ? D3D11_CLEAR_STENCIL : 0); + FLOAT depthClear = gl::clamp01(clearParams.depthClearValue); + UINT8 stencilClear = clearParams.stencilClearValue & 0xFF; + + deviceContext->ClearDepthStencilView(framebufferDSV, clearFlags, depthClear, stencilClear); + } + } + } + + if (maskedClearRenderTargets.size() > 0 || maskedClearDepthStencil) + { + // To clear the render targets and depth stencil in one pass: + // + // Render a quad clipped to the scissor rectangle which draws the clear color and a blend + // state that will perform the required color masking. + // + // The quad's depth is equal to the depth clear value with a depth stencil state that + // will enable or disable depth test/writes if the depth buffer should be cleared or not. + // + // The rasterizer state's stencil is set to always pass or fail based on if the stencil + // should be cleared or not with a stencil write mask of the stencil clear value. + // + // ====================================================================================== + // + // Luckily, the gl spec (ES 3.0.2 pg 183) states that the results of clearing a render- + // buffer that is not normalized fixed point or floating point with floating point values + // are undefined so we can just write floats to them and D3D11 will bit cast them to + // integers. + // + // Also, we don't have to worry about attempting to clear a normalized fixed/floating point + // buffer with integer values because there is no gl API call which would allow it, + // glClearBuffer* calls only clear a single renderbuffer at a time which is verified to + // be a compatible clear type. + + // Bind all the render targets which need clearing + ASSERT(maskedClearRenderTargets.size() <= mRenderer->getRendererCaps().maxDrawBuffers); + std::vector<ID3D11RenderTargetView*> rtvs(maskedClearRenderTargets.size()); + for (unsigned int i = 0; i < maskedClearRenderTargets.size(); i++) + { + RenderTarget11 *renderTarget = maskedClearRenderTargets[i].renderTarget; + ID3D11RenderTargetView *rtv = renderTarget->getRenderTargetView(); + if (!rtv) + { + ERR("Render target view unexpectedly null."); + return; + } + + rtvs[i] = rtv; + } + ID3D11DepthStencilView *dsv = maskedClearDepthStencil ? maskedClearDepthStencil->getDepthStencilView() : NULL; + + ID3D11BlendState *blendState = getBlendState(maskedClearRenderTargets); + const FLOAT blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + const UINT sampleMask = 0xFFFFFFFF; + + ID3D11DepthStencilState *dsState = getDepthStencilState(clearParams); + const UINT stencilClear = clearParams.stencilClearValue & 0xFF; + + // Set the vertices + UINT vertexStride = 0; + const UINT startIdx = 0; + const ClearShader* shader = NULL; + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + ERR("Failed to map masked clear vertex buffer, HRESULT: 0x%X.", result); + return; + } + + const gl::Rectangle *scissorPtr = clearParams.scissorEnabled ? &clearParams.scissor : NULL; + switch (clearParams.colorClearType) + { + case GL_FLOAT: + ApplyVertices(framebufferSize, scissorPtr, clearParams.colorFClearValue, clearParams.depthClearValue, mappedResource.pData); + vertexStride = sizeof(d3d11::PositionDepthColorVertex<float>); + shader = &mFloatClearShader; + break; + + case GL_UNSIGNED_INT: + ApplyVertices(framebufferSize, scissorPtr, clearParams.colorUIClearValue, clearParams.depthClearValue, mappedResource.pData); + vertexStride = sizeof(d3d11::PositionDepthColorVertex<unsigned int>); + shader = &mUintClearShader; + break; + + case GL_INT: + ApplyVertices(framebufferSize, scissorPtr, clearParams.colorIClearValue, clearParams.depthClearValue, mappedResource.pData); + vertexStride = sizeof(d3d11::PositionDepthColorVertex<int>); + shader = &mIntClearShader; + break; + + default: + UNREACHABLE(); + break; + } + + deviceContext->Unmap(mVertexBuffer, 0); + + // Set the viewport to be the same size as the framebuffer + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = framebufferSize.width; + viewport.Height = framebufferSize.height; + viewport.MinDepth = 0; + viewport.MaxDepth = 1; + deviceContext->RSSetViewports(1, &viewport); + + // Apply state + deviceContext->OMSetBlendState(blendState, blendFactors, sampleMask); + deviceContext->OMSetDepthStencilState(dsState, stencilClear); + deviceContext->RSSetState(mRasterizerState); + + // Apply shaders + deviceContext->IASetInputLayout(shader->inputLayout); + deviceContext->VSSetShader(shader->vertexShader, NULL, 0); + deviceContext->PSSetShader(shader->pixelShader, NULL, 0); + deviceContext->GSSetShader(NULL, NULL, 0); + + // Apply vertex buffer + deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &vertexStride, &startIdx); + deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + // Apply render targets + deviceContext->OMSetRenderTargets(rtvs.size(), (rtvs.empty() ? NULL : &rtvs[0]), dsv); + + // Draw the clear quad + deviceContext->Draw(4, 0); + + // Clean up + mRenderer->markAllStateDirty(); + } +} + +ID3D11BlendState *Clear11::getBlendState(const std::vector<MaskedRenderTarget>& rts) +{ + ClearBlendInfo blendKey = { 0 }; + for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + if (i < rts.size()) + { + RenderTarget11 *rt = rts[i].renderTarget; + GLint internalFormat = rt->getInternalFormat(); + + blendKey.maskChannels[i][0] = (rts[i].colorMask[0] && gl::GetRedBits(internalFormat) > 0); + blendKey.maskChannels[i][1] = (rts[i].colorMask[1] && gl::GetGreenBits(internalFormat) > 0); + blendKey.maskChannels[i][2] = (rts[i].colorMask[2] && gl::GetBlueBits(internalFormat) > 0); + blendKey.maskChannels[i][3] = (rts[i].colorMask[3] && gl::GetAlphaBits(internalFormat) > 0); + } + else + { + blendKey.maskChannels[i][0] = false; + blendKey.maskChannels[i][1] = false; + blendKey.maskChannels[i][2] = false; + blendKey.maskChannels[i][3] = false; + } + } + + ClearBlendStateMap::const_iterator i = mClearBlendStates.find(blendKey); + if (i != mClearBlendStates.end()) + { + return i->second; + } + else + { + D3D11_BLEND_DESC blendDesc = { 0 }; + blendDesc.AlphaToCoverageEnable = FALSE; + blendDesc.IndependentBlendEnable = (rts.size() > 1) ? TRUE : FALSE; + + for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + blendDesc.RenderTarget[i].BlendEnable = FALSE; + blendDesc.RenderTarget[i].RenderTargetWriteMask = gl_d3d11::ConvertColorMask(blendKey.maskChannels[i][0], + blendKey.maskChannels[i][1], + blendKey.maskChannels[i][2], + blendKey.maskChannels[i][3]); + } + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11BlendState* blendState = NULL; + HRESULT result = device->CreateBlendState(&blendDesc, &blendState); + if (FAILED(result) || !blendState) + { + ERR("Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result); + return NULL; + } + + mClearBlendStates[blendKey] = blendState; + + return blendState; + } +} + +ID3D11DepthStencilState *Clear11::getDepthStencilState(const gl::ClearParameters &clearParams) +{ + ClearDepthStencilInfo dsKey = { 0 }; + dsKey.clearDepth = clearParams.clearDepth; + dsKey.clearStencil = clearParams.clearStencil; + dsKey.stencilWriteMask = clearParams.stencilWriteMask & 0xFF; + + ClearDepthStencilStateMap::const_iterator i = mClearDepthStencilStates.find(dsKey); + if (i != mClearDepthStencilStates.end()) + { + return i->second; + } + else + { + D3D11_DEPTH_STENCIL_DESC dsDesc = { 0 }; + dsDesc.DepthEnable = dsKey.clearDepth ? TRUE : FALSE; + dsDesc.DepthWriteMask = dsKey.clearDepth ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.StencilEnable = dsKey.clearStencil ? TRUE : FALSE; + dsDesc.StencilReadMask = 0; + dsDesc.StencilWriteMask = dsKey.stencilWriteMask; + dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DepthStencilState* dsState = NULL; + HRESULT result = device->CreateDepthStencilState(&dsDesc, &dsState); + if (FAILED(result) || !dsState) + { + ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result); + return NULL; + } + + mClearDepthStencilStates[dsKey] = dsState; + + return dsState; + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.h new file mode 100644 index 0000000000..0cb9a85a6d --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.h @@ -0,0 +1,83 @@ +// +// 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. +// + +// Clear11.h: Framebuffer clear utility class. + +#ifndef LIBGLESV2_RENDERER_CLEAR11_H_ +#define LIBGLESV2_RENDERER_CLEAR11_H_ + +#include "libGLESv2/angletypes.h" + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ +class Renderer11; +class RenderTarget11; + +class Clear11 +{ + public: + explicit Clear11(Renderer11 *renderer); + ~Clear11(); + + // Clears the framebuffer with the supplied clear parameters, assumes that the framebuffer is currently applied. + void clearFramebuffer(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer); + + private: + Renderer11 *mRenderer; + + struct ClearBlendInfo + { + bool maskChannels[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT][4]; + }; + typedef bool (*ClearBlendInfoComparisonFunction)(const ClearBlendInfo&, const ClearBlendInfo &); + typedef std::map<ClearBlendInfo, ID3D11BlendState*, ClearBlendInfoComparisonFunction> ClearBlendStateMap; + ClearBlendStateMap mClearBlendStates; + + struct MaskedRenderTarget + { + bool colorMask[4]; + RenderTarget11 *renderTarget; + }; + + ID3D11BlendState *getBlendState(const std::vector<MaskedRenderTarget> &rts); + + struct ClearShader + { + ID3D11InputLayout *inputLayout; + ID3D11VertexShader *vertexShader; + ID3D11PixelShader *pixelShader; + }; + ClearShader mFloatClearShader; + ClearShader mUintClearShader; + ClearShader mIntClearShader; + + template <unsigned int vsSize, unsigned int psSize> + static ClearShader CreateClearShader(ID3D11Device *device, DXGI_FORMAT colorType, const BYTE (&vsByteCode)[vsSize], const BYTE (&psByteCode)[psSize]); + + struct ClearDepthStencilInfo + { + bool clearDepth; + bool clearStencil; + UINT8 stencilWriteMask; + }; + typedef bool (*ClearDepthStencilInfoComparisonFunction)(const ClearDepthStencilInfo&, const ClearDepthStencilInfo &); + typedef std::map<ClearDepthStencilInfo, ID3D11DepthStencilState*, ClearDepthStencilInfoComparisonFunction> ClearDepthStencilStateMap; + ClearDepthStencilStateMap mClearDepthStencilStates; + + ID3D11DepthStencilState *getDepthStencilState(const gl::ClearParameters &clearParams); + + ID3D11Buffer *mVertexBuffer; + ID3D11RasterizerState *mRasterizerState; +}; + +} + +#endif // LIBGLESV2_RENDERER_CLEAR11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp new file mode 100644 index 0000000000..8698776650 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp @@ -0,0 +1,71 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Fence11.cpp: Defines the rx::Fence11 class which implements rx::FenceImpl. + +#include "libGLESv2/renderer/d3d/d3d11/Fence11.h" +#include "libGLESv2/main.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ + +Fence11::Fence11(rx::Renderer11 *renderer) +{ + mRenderer = renderer; + mQuery = NULL; +} + +Fence11::~Fence11() +{ + SafeRelease(mQuery); +} + +bool Fence11::isSet() const +{ + return mQuery != NULL; +} + +void Fence11::set() +{ + if (!mQuery) + { + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = D3D11_QUERY_EVENT; + queryDesc.MiscFlags = 0; + + if (FAILED(mRenderer->getDevice()->CreateQuery(&queryDesc, &mQuery))) + { + return gl::error(GL_OUT_OF_MEMORY); + } + } + + mRenderer->getDeviceContext()->End(mQuery); +} + +bool Fence11::test(bool flushCommandBuffer) +{ + ASSERT(mQuery); + + UINT getDataFlags = (flushCommandBuffer ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH); + HRESULT result = mRenderer->getDeviceContext()->GetData(mQuery, NULL, 0, getDataFlags); + + if (mRenderer->isDeviceLost()) + { + return gl::error(GL_OUT_OF_MEMORY, true); + } + + ASSERT(result == S_OK || result == S_FALSE); + return (result == S_OK); +} + +bool Fence11::hasError() const +{ + return mRenderer->isDeviceLost(); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.h new file mode 100644 index 0000000000..50c7621776 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.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. +// + +// Fence11.h: Defines the rx::Fence11 class which implements rx::FenceImpl. + +#ifndef LIBGLESV2_RENDERER_Fence11_H_ +#define LIBGLESV2_RENDERER_Fence11_H_ + +#include "libGLESv2/renderer/FenceImpl.h" + +namespace rx +{ +class Renderer11; + +class Fence11 : public FenceImpl +{ + public: + explicit Fence11(rx::Renderer11 *renderer); + virtual ~Fence11(); + + bool isSet() const; + void set(); + bool test(bool flushCommandBuffer); + bool hasError() const; + + private: + DISALLOW_COPY_AND_ASSIGN(Fence11); + + rx::Renderer11 *mRenderer; + ID3D11Query *mQuery; +}; + +} + +#endif // LIBGLESV2_RENDERER_FENCE11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp new file mode 100644 index 0000000000..2165bec305 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp @@ -0,0 +1,460 @@ +#include "precompiled.h" +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Image11.h: Implements the rx::Image11 class, which acts as the interface to +// the actual underlying resources of a Texture + +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/Image11.h" +#include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" + +#include "libGLESv2/main.h" +#include "common/utilities.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" + +namespace rx +{ + +Image11::Image11() +{ + mStagingTexture = NULL; + mRenderer = NULL; + mDXGIFormat = DXGI_FORMAT_UNKNOWN; +} + +Image11::~Image11() +{ + SafeRelease(mStagingTexture); +} + +Image11 *Image11::makeImage11(Image *img) +{ + ASSERT(HAS_DYNAMIC_TYPE(rx::Image11*, img)); + return static_cast<rx::Image11*>(img); +} + +void Image11::generateMipmap(Image11 *dest, Image11 *src) +{ + ASSERT(src->getDXGIFormat() == dest->getDXGIFormat()); + ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth()); + ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight()); + + MipGenerationFunction mipFunction = d3d11::GetMipGenerationFunction(src->getDXGIFormat()); + ASSERT(mipFunction != NULL); + + D3D11_MAPPED_SUBRESOURCE destMapped; + HRESULT destMapResult = dest->map(D3D11_MAP_WRITE, &destMapped); + if (FAILED(destMapResult)) + { + ERR("Failed to map destination image for mip map generation. HRESULT:0x%X", destMapResult); + return; + } + + D3D11_MAPPED_SUBRESOURCE srcMapped; + HRESULT srcMapResult = src->map(D3D11_MAP_READ, &srcMapped); + if (FAILED(srcMapResult)) + { + ERR("Failed to map source image for mip map generation. HRESULT:0x%X", srcMapResult); + + dest->unmap(); + return; + } + + const uint8_t *sourceData = reinterpret_cast<const uint8_t*>(srcMapped.pData); + uint8_t *destData = reinterpret_cast<uint8_t*>(destMapped.pData); + + mipFunction(src->getWidth(), src->getHeight(), src->getDepth(), sourceData, srcMapped.RowPitch, srcMapped.DepthPitch, + destData, destMapped.RowPitch, destMapped.DepthPitch); + + dest->unmap(); + src->unmap(); + + dest->markDirty(); +} + +bool Image11::isDirty() const +{ + // Make sure that this image is marked as dirty even if the staging texture hasn't been created yet + // if initialization is required before use. + return (mDirty && (mStagingTexture || gl_d3d11::RequiresTextureDataInitialization(mInternalFormat))); +} + +bool Image11::copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance()); + return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, 0, width, height, 1); +} + +bool Image11::copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance()); + return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, face, xoffset, yoffset, 0, width, height, 1); +} + +bool Image11::copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) +{ + TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage->getStorageInstance()); + return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, zoffset, width, height, depth); +} + +bool Image11::copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height) +{ + TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage->getStorageInstance()); + return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, arrayLayer, xoffset, yoffset, 0, width, height, 1); +} + +bool Image11::redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) +{ + if (mWidth != width || + mHeight != height || + mInternalFormat != internalformat || + forceRelease) + { + mRenderer = Renderer11::makeRenderer11(renderer); + + mWidth = width; + mHeight = height; + mDepth = depth; + mInternalFormat = internalformat; + mTarget = target; + + // compute the d3d format that will be used + mDXGIFormat = gl_d3d11::GetTexFormat(internalformat); + mActualFormat = d3d11_gl::GetInternalFormat(mDXGIFormat); + mRenderable = gl_d3d11::GetRTVFormat(internalformat) != DXGI_FORMAT_UNKNOWN; + + SafeRelease(mStagingTexture); + mDirty = gl_d3d11::RequiresTextureDataInitialization(mInternalFormat); + + return true; + } + + return false; +} + +DXGI_FORMAT Image11::getDXGIFormat() const +{ + // this should only happen if the image hasn't been redefined first + // which would be a bug by the caller + ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN); + + return mDXGIFormat; +} + +// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input +// into the target pixel rectangle. +void Image11::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint unpackAlignment, GLenum type, const void *input) +{ + GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, type, width, unpackAlignment); + GLsizei inputDepthPitch = gl::GetDepthPitch(mInternalFormat, type, width, height, unpackAlignment); + GLuint outputPixelSize = d3d11::GetFormatPixelBytes(mDXGIFormat); + + LoadImageFunction loadFunction = d3d11::GetImageLoadFunction(mInternalFormat, type); + ASSERT(loadFunction != NULL); + + D3D11_MAPPED_SUBRESOURCE mappedImage; + HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); + if (FAILED(result)) + { + ERR("Could not map image for loading."); + return; + } + + uint8_t* offsetMappedData = (reinterpret_cast<uint8_t*>(mappedImage.pData) + (yoffset * mappedImage.RowPitch + xoffset * outputPixelSize + zoffset * mappedImage.DepthPitch)); + loadFunction(width, height, depth, + reinterpret_cast<const uint8_t*>(input), inputRowPitch, inputDepthPitch, + offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); + + unmap(); +} + +void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + const void *input) +{ + GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, GL_UNSIGNED_BYTE, width, 1); + GLsizei inputDepthPitch = gl::GetDepthPitch(mInternalFormat, GL_UNSIGNED_BYTE, width, height, 1); + + GLuint outputPixelSize = d3d11::GetFormatPixelBytes(mDXGIFormat); + GLuint outputBlockWidth = d3d11::GetBlockWidth(mDXGIFormat); + GLuint outputBlockHeight = d3d11::GetBlockHeight(mDXGIFormat); + + ASSERT(xoffset % outputBlockWidth == 0); + ASSERT(yoffset % outputBlockHeight == 0); + + LoadImageFunction loadFunction = d3d11::GetImageLoadFunction(mInternalFormat, GL_UNSIGNED_BYTE); + ASSERT(loadFunction != NULL); + + D3D11_MAPPED_SUBRESOURCE mappedImage; + HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); + if (FAILED(result)) + { + ERR("Could not map image for loading."); + return; + } + + uint8_t* offsetMappedData = reinterpret_cast<uint8_t*>(mappedImage.pData) + ((yoffset / outputBlockHeight) * mappedImage.RowPitch + + (xoffset / outputBlockWidth) * outputPixelSize + + zoffset * mappedImage.DepthPitch); + + loadFunction(width, height, depth, + reinterpret_cast<const uint8_t*>(input), inputRowPitch, inputDepthPitch, + offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); + + unmap(); +} + +void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +{ + gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer(); + + if (colorbuffer && colorbuffer->getActualFormat() == mActualFormat) + { + // No conversion needed-- use copyback fastpath + ID3D11Texture2D *colorBufferTexture = NULL; + unsigned int subresourceIndex = 0; + + if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture)) + { + D3D11_TEXTURE2D_DESC textureDesc; + colorBufferTexture->GetDesc(&textureDesc); + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + ID3D11Texture2D* srcTex = NULL; + if (textureDesc.SampleDesc.Count > 1) + { + D3D11_TEXTURE2D_DESC resolveDesc; + resolveDesc.Width = textureDesc.Width; + resolveDesc.Height = textureDesc.Height; + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; + resolveDesc.Format = textureDesc.Format; + resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Quality = 0; + resolveDesc.Usage = D3D11_USAGE_DEFAULT; + resolveDesc.BindFlags = 0; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex); + if (FAILED(result)) + { + ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result); + return; + } + + deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format); + subresourceIndex = 0; + } + else + { + srcTex = colorBufferTexture; + srcTex->AddRef(); + } + + D3D11_BOX srcBox; + srcBox.left = x; + srcBox.right = x + width; + srcBox.top = y; + srcBox.bottom = y + height; + srcBox.front = 0; + srcBox.back = 1; + + deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, zoffset, srcTex, subresourceIndex, &srcBox); + + SafeRelease(srcTex); + SafeRelease(colorBufferTexture); + } + } + else + { + // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels + D3D11_MAPPED_SUBRESOURCE mappedImage; + HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); + if (FAILED(result)) + { + ERR("Failed to map texture for Image11::copy, HRESULT: 0x%X.", result); + return; + } + + // determine the offset coordinate into the destination buffer + GLsizei rowOffset = gl::GetPixelBytes(mActualFormat) * xoffset; + void *dataOffset = static_cast<unsigned char*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset + zoffset * mappedImage.DepthPitch; + + GLenum format = gl::GetFormat(mInternalFormat); + GLenum type = gl::GetType(mInternalFormat); + + mRenderer->readPixels(source, x, y, width, height, format, type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset); + + unmap(); + } +} + +ID3D11Resource *Image11::getStagingTexture() +{ + createStagingTexture(); + + return mStagingTexture; +} + +unsigned int Image11::getStagingSubresource() +{ + createStagingTexture(); + + return mStagingSubresource; +} + +void Image11::createStagingTexture() +{ + if (mStagingTexture) + { + return; + } + + const DXGI_FORMAT dxgiFormat = getDXGIFormat(); + + if (mWidth > 0 && mHeight > 0 && mDepth > 0) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + int lodOffset = 1; + GLsizei width = mWidth; + GLsizei height = mHeight; + + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset); + + if (mTarget == GL_TEXTURE_3D) + { + ID3D11Texture3D *newTexture = NULL; + + D3D11_TEXTURE3D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.Depth = mDepth; + desc.MipLevels = lodOffset + 1; + desc.Format = dxgiFormat; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + + if (gl_d3d11::RequiresTextureDataInitialization(mInternalFormat)) + { + std::vector<D3D11_SUBRESOURCE_DATA> initialData; + std::vector< std::vector<BYTE> > textureData; + d3d11::GenerateInitialTextureData(mInternalFormat, width, height, mDepth, + lodOffset + 1, &initialData, &textureData); + + result = device->CreateTexture3D(&desc, initialData.data(), &newTexture); + } + else + { + result = device->CreateTexture3D(&desc, NULL, &newTexture); + } + + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + ERR("Creating image failed."); + return gl::error(GL_OUT_OF_MEMORY); + } + + mStagingTexture = newTexture; + mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); + } + else if (mTarget == GL_TEXTURE_2D || mTarget == GL_TEXTURE_2D_ARRAY || mTarget == GL_TEXTURE_CUBE_MAP) + { + ID3D11Texture2D *newTexture = NULL; + + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.MipLevels = lodOffset + 1; + desc.ArraySize = 1; + desc.Format = dxgiFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + + if (gl_d3d11::RequiresTextureDataInitialization(mInternalFormat)) + { + std::vector<D3D11_SUBRESOURCE_DATA> initialData; + std::vector< std::vector<BYTE> > textureData; + d3d11::GenerateInitialTextureData(mInternalFormat, width, height, 1, + lodOffset + 1, &initialData, &textureData); + + result = device->CreateTexture2D(&desc, initialData.data(), &newTexture); + } + else + { + result = device->CreateTexture2D(&desc, NULL, &newTexture); + } + + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + ERR("Creating image failed."); + return gl::error(GL_OUT_OF_MEMORY); + } + + mStagingTexture = newTexture; + mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); + } + else + { + UNREACHABLE(); + } + } + + mDirty = false; +} + +HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) +{ + createStagingTexture(); + + HRESULT result = E_FAIL; + + if (mStagingTexture) + { + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + result = deviceContext->Map(mStagingTexture, mStagingSubresource, mapType, 0, map); + + // this can fail if the device is removed (from TDR) + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + } + else if (SUCCEEDED(result)) + { + mDirty = true; + } + } + + return result; +} + +void Image11::unmap() +{ + if (mStagingTexture) + { + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->Unmap(mStagingTexture, mStagingSubresource); + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h new file mode 100644 index 0000000000..7d873a2794 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h @@ -0,0 +1,77 @@ +// +// 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. +// + +// Image11.h: Defines the rx::Image11 class, which acts as the interface to +// the actual underlying resources of a Texture + +#ifndef LIBGLESV2_RENDERER_IMAGE11_H_ +#define LIBGLESV2_RENDERER_IMAGE11_H_ + +#include "libGLESv2/renderer/d3d/ImageD3D.h" + +#include "common/debug.h" + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ +class Renderer; +class Renderer11; +class TextureStorageInterface2D; +class TextureStorageInterfaceCube; + +class Image11 : public ImageD3D +{ + public: + Image11(); + virtual ~Image11(); + + static Image11 *makeImage11(Image *img); + + static void generateMipmap(Image11 *dest, Image11 *src); + + virtual bool isDirty() const; + + virtual bool copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + virtual bool copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + virtual bool copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); + virtual bool copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height); + + virtual bool redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease); + + DXGI_FORMAT getDXGIFormat() const; + + virtual void loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint unpackAlignment, GLenum type, const void *input); + virtual void loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + const void *input); + + virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + + protected: + HRESULT map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map); + void unmap(); + + private: + DISALLOW_COPY_AND_ASSIGN(Image11); + + ID3D11Resource *getStagingTexture(); + unsigned int getStagingSubresource(); + void createStagingTexture(); + + Renderer11 *mRenderer; + + DXGI_FORMAT mDXGIFormat; + ID3D11Resource *mStagingTexture; + unsigned int mStagingSubresource; +}; + +} + +#endif // LIBGLESV2_RENDERER_IMAGE11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.cpp new file mode 100644 index 0000000000..03e4e6611b --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.cpp @@ -0,0 +1,175 @@ +#include "precompiled.h" +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// IndexBuffer11.cpp: Defines the D3D11 IndexBuffer implementation. + +#include "libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ + +IndexBuffer11::IndexBuffer11(Renderer11 *const renderer) : mRenderer(renderer) +{ + mBuffer = NULL; + mBufferSize = 0; + mDynamicUsage = false; +} + +IndexBuffer11::~IndexBuffer11() +{ + SafeRelease(mBuffer); +} + +bool IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) +{ + SafeRelease(mBuffer); + + updateSerial(); + + if (bufferSize > 0) + { + ID3D11Device* dxDevice = mRenderer->getDevice(); + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = bufferSize; + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + + HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); + if (FAILED(result)) + { + return false; + } + } + + mBufferSize = bufferSize; + mIndexType = indexType; + mDynamicUsage = dynamic; + + return true; +} + +IndexBuffer11 *IndexBuffer11::makeIndexBuffer11(IndexBuffer *indexBuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(IndexBuffer11*, indexBuffer)); + return static_cast<IndexBuffer11*>(indexBuffer); +} + +bool IndexBuffer11::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory) +{ + if (mBuffer) + { + // Check for integer overflows and out-out-bounds map requests + if (offset + size < offset || offset + size > mBufferSize) + { + ERR("Index buffer map range is not inside the buffer."); + return false; + } + + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); + if (FAILED(result)) + { + ERR("Index buffer map failed with error 0x%08x", result); + return false; + } + + *outMappedMemory = reinterpret_cast<char*>(mappedResource.pData) + offset; + return true; + } + else + { + ERR("Index buffer not initialized."); + return false; + } +} + +bool IndexBuffer11::unmapBuffer() +{ + if (mBuffer) + { + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + dxContext->Unmap(mBuffer, 0); + return true; + } + else + { + ERR("Index buffer not initialized."); + return false; + } +} + +GLenum IndexBuffer11::getIndexType() const +{ + return mIndexType; +} + +unsigned int IndexBuffer11::getBufferSize() const +{ + return mBufferSize; +} + +bool IndexBuffer11::setSize(unsigned int bufferSize, GLenum indexType) +{ + if (bufferSize > mBufferSize || indexType != mIndexType) + { + return initialize(bufferSize, indexType, mDynamicUsage); + } + else + { + return true; + } +} + +bool IndexBuffer11::discard() +{ + if (mBuffer) + { + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + ERR("Index buffer map failed with error 0x%08x", result); + return false; + } + + dxContext->Unmap(mBuffer, 0); + + return true; + } + else + { + ERR("Index buffer not initialized."); + return false; + } +} + +DXGI_FORMAT IndexBuffer11::getIndexFormat() const +{ + switch (mIndexType) + { + case GL_UNSIGNED_BYTE: return DXGI_FORMAT_R16_UINT; + case GL_UNSIGNED_SHORT: return DXGI_FORMAT_R16_UINT; + case GL_UNSIGNED_INT: return DXGI_FORMAT_R32_UINT; + default: UNREACHABLE(); return DXGI_FORMAT_UNKNOWN; + } +} + +ID3D11Buffer *IndexBuffer11::getBuffer() const +{ + return mBuffer; +} + +}
\ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h new file mode 100644 index 0000000000..e821b7f3d1 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h @@ -0,0 +1,53 @@ +// +// 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. +// + +// IndexBuffer11.h: Defines the D3D11 IndexBuffer implementation. + +#ifndef LIBGLESV2_RENDERER_INDEXBUFFER11_H_ +#define LIBGLESV2_RENDERER_INDEXBUFFER11_H_ + +#include "libGLESv2/renderer/d3d/IndexBuffer.h" + +namespace rx +{ +class Renderer11; + +class IndexBuffer11 : public IndexBuffer +{ + public: + explicit IndexBuffer11(Renderer11 *const renderer); + virtual ~IndexBuffer11(); + + virtual bool initialize(unsigned int bufferSize, GLenum indexType, bool dynamic); + + static IndexBuffer11 *makeIndexBuffer11(IndexBuffer *indexBuffer); + + virtual bool mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory); + virtual bool unmapBuffer(); + + virtual GLenum getIndexType() const; + virtual unsigned int getBufferSize() const; + virtual bool setSize(unsigned int bufferSize, GLenum indexType); + + virtual bool discard(); + + DXGI_FORMAT getIndexFormat() const; + ID3D11Buffer *getBuffer() const; + + private: + DISALLOW_COPY_AND_ASSIGN(IndexBuffer11); + + rx::Renderer11 *const mRenderer; + + ID3D11Buffer *mBuffer; + unsigned int mBufferSize; + GLenum mIndexType; + bool mDynamicUsage; +}; + +} + +#endif // LIBGLESV2_RENDERER_INDEXBUFFER11_H_
\ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp new file mode 100644 index 0000000000..3536fafac9 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp @@ -0,0 +1,248 @@ +#include "precompiled.h" +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// InputLayoutCache.cpp: Defines InputLayoutCache, a class that builds and caches +// D3D11 input layouts. + +#include "libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h" +#include "libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h" +#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" +#include "libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h" +#include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/renderer/d3d/VertexDataManager.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" + +#include "third_party/murmurhash/MurmurHash3.h" + +namespace rx +{ + +static void GetInputLayout(const TranslatedAttribute translatedAttributes[gl::MAX_VERTEX_ATTRIBS], + gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]) +{ + for (unsigned int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + { + const TranslatedAttribute &translatedAttribute = translatedAttributes[attributeIndex]; + + if (translatedAttributes[attributeIndex].active) + { + inputLayout[attributeIndex] = gl::VertexFormat(*translatedAttribute.attribute, + translatedAttribute.currentValueType); + } + } +} + +const unsigned int InputLayoutCache::kMaxInputLayouts = 1024; + +InputLayoutCache::InputLayoutCache() : mInputLayoutMap(kMaxInputLayouts, hashInputLayout, compareInputLayouts) +{ + mCounter = 0; + mDevice = NULL; + mDeviceContext = NULL; + mCurrentIL = NULL; + for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mCurrentBuffers[i] = NULL; + mCurrentVertexStrides[i] = -1; + mCurrentVertexOffsets[i] = -1; + } +} + +InputLayoutCache::~InputLayoutCache() +{ + clear(); +} + +void InputLayoutCache::initialize(ID3D11Device *device, ID3D11DeviceContext *context) +{ + clear(); + mDevice = device; + mDeviceContext = context; +} + +void InputLayoutCache::clear() +{ + for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++) + { + SafeRelease(i->second.inputLayout); + } + mInputLayoutMap.clear(); + markDirty(); +} + +void InputLayoutCache::markDirty() +{ + mCurrentIL = NULL; + for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mCurrentBuffers[i] = NULL; + mCurrentVertexStrides[i] = -1; + mCurrentVertexOffsets[i] = -1; + } +} + +GLenum InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS], + gl::ProgramBinary *programBinary) +{ + int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS]; + programBinary->sortAttributesByLayout(attributes, sortedSemanticIndices); + + if (!mDevice || !mDeviceContext) + { + ERR("InputLayoutCache is not initialized."); + return GL_INVALID_OPERATION; + } + + InputLayoutKey ilKey = { 0 }; + + static const char* semanticName = "TEXCOORD"; + + for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + if (attributes[i].active) + { + D3D11_INPUT_CLASSIFICATION inputClass = attributes[i].divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA; + + gl::VertexFormat vertexFormat(*attributes[i].attribute, attributes[i].currentValueType); + DXGI_FORMAT dxgiFormat = gl_d3d11::GetNativeVertexFormat(vertexFormat); + + // Record the type of the associated vertex shader vector in our key + // This will prevent mismatched vertex shaders from using the same input layout + GLint attributeSize; + programBinary->getActiveAttribute(sortedSemanticIndices[i], 0, NULL, &attributeSize, &ilKey.elements[ilKey.elementCount].glslElementType, NULL); + + ilKey.elements[ilKey.elementCount].desc.SemanticName = semanticName; + ilKey.elements[ilKey.elementCount].desc.SemanticIndex = i; + ilKey.elements[ilKey.elementCount].desc.Format = dxgiFormat; + ilKey.elements[ilKey.elementCount].desc.InputSlot = i; + ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0; + ilKey.elements[ilKey.elementCount].desc.InputSlotClass = inputClass; + ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = attributes[i].divisor; + ilKey.elementCount++; + } + } + + ID3D11InputLayout *inputLayout = NULL; + + InputLayoutMap::iterator keyIter = mInputLayoutMap.find(ilKey); + if (keyIter != mInputLayoutMap.end()) + { + inputLayout = keyIter->second.inputLayout; + keyIter->second.lastUsedTime = mCounter++; + } + else + { + gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS]; + GetInputLayout(attributes, shaderInputLayout); + ShaderExecutable11 *shader = ShaderExecutable11::makeShaderExecutable11(programBinary->getVertexExecutableForInputLayout(shaderInputLayout)); + + D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS]; + for (unsigned int j = 0; j < ilKey.elementCount; ++j) + { + descs[j] = ilKey.elements[j].desc; + } + + HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader->getFunction(), shader->getLength(), &inputLayout); + if (FAILED(result)) + { + ERR("Failed to crate input layout, result: 0x%08x", result); + return GL_INVALID_OPERATION; + } + + if (mInputLayoutMap.size() >= kMaxInputLayouts) + { + TRACE("Overflowed the limit of %u input layouts, removing the least recently used " + "to make room.", kMaxInputLayouts); + + InputLayoutMap::iterator leastRecentlyUsed = mInputLayoutMap.begin(); + for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++) + { + if (i->second.lastUsedTime < leastRecentlyUsed->second.lastUsedTime) + { + leastRecentlyUsed = i; + } + } + SafeRelease(leastRecentlyUsed->second.inputLayout); + mInputLayoutMap.erase(leastRecentlyUsed); + } + + InputLayoutCounterPair inputCounterPair; + inputCounterPair.inputLayout = inputLayout; + inputCounterPair.lastUsedTime = mCounter++; + + mInputLayoutMap.insert(std::make_pair(ilKey, inputCounterPair)); + } + + if (inputLayout != mCurrentIL) + { + mDeviceContext->IASetInputLayout(inputLayout); + mCurrentIL = inputLayout; + } + + bool dirtyBuffers = false; + size_t minDiff = gl::MAX_VERTEX_ATTRIBS; + size_t maxDiff = 0; + for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + ID3D11Buffer *buffer = NULL; + + if (attributes[i].active) + { + VertexBuffer11 *vertexBuffer = VertexBuffer11::makeVertexBuffer11(attributes[i].vertexBuffer); + Buffer11 *bufferStorage = attributes[i].storage ? Buffer11::makeBuffer11(attributes[i].storage) : NULL; + + buffer = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK) + : vertexBuffer->getBuffer(); + } + + UINT vertexStride = attributes[i].stride; + UINT vertexOffset = attributes[i].offset; + + if (buffer != mCurrentBuffers[i] || vertexStride != mCurrentVertexStrides[i] || + vertexOffset != mCurrentVertexOffsets[i]) + { + dirtyBuffers = true; + minDiff = std::min(minDiff, static_cast<size_t>(i)); + maxDiff = std::max(maxDiff, static_cast<size_t>(i)); + + mCurrentBuffers[i] = buffer; + mCurrentVertexStrides[i] = vertexStride; + mCurrentVertexOffsets[i] = vertexOffset; + } + } + + if (dirtyBuffers) + { + ASSERT(minDiff <= maxDiff && maxDiff < gl::MAX_VERTEX_ATTRIBS); + mDeviceContext->IASetVertexBuffers(minDiff, maxDiff - minDiff + 1, mCurrentBuffers + minDiff, + mCurrentVertexStrides + minDiff, mCurrentVertexOffsets + minDiff); + } + + return GL_NO_ERROR; +} + +std::size_t InputLayoutCache::hashInputLayout(const InputLayoutKey &inputLayout) +{ + static const unsigned int seed = 0xDEADBEEF; + + std::size_t hash = 0; + MurmurHash3_x86_32(inputLayout.begin(), inputLayout.end() - inputLayout.begin(), seed, &hash); + return hash; +} + +bool InputLayoutCache::compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b) +{ + if (a.elementCount != b.elementCount) + { + return false; + } + + return std::equal(a.begin(), a.end(), b.begin()); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h new file mode 100644 index 0000000000..5d0ac60537 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h @@ -0,0 +1,95 @@ +// +// 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. +// + +// InputLayoutCache.h: Defines InputLayoutCache, a class that builds and caches +// D3D11 input layouts. + +#ifndef LIBGLESV2_RENDERER_INPUTLAYOUTCACHE_H_ +#define LIBGLESV2_RENDERER_INPUTLAYOUTCACHE_H_ + +#include "libGLESv2/Constants.h" +#include "common/angleutils.h" + +namespace gl +{ +class ProgramBinary; +} + +namespace rx +{ +struct TranslatedAttribute; + +class InputLayoutCache +{ + public: + InputLayoutCache(); + virtual ~InputLayoutCache(); + + void initialize(ID3D11Device *device, ID3D11DeviceContext *context); + void clear(); + void markDirty(); + + GLenum applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS], + gl::ProgramBinary *programBinary); + + private: + DISALLOW_COPY_AND_ASSIGN(InputLayoutCache); + + struct InputLayoutElement + { + D3D11_INPUT_ELEMENT_DESC desc; + GLenum glslElementType; + }; + + struct InputLayoutKey + { + unsigned int elementCount; + InputLayoutElement elements[gl::MAX_VERTEX_ATTRIBS]; + + const char *begin() const + { + return reinterpret_cast<const char*>(&elementCount); + } + + const char *end() const + { + return reinterpret_cast<const char*>(&elements[elementCount]); + } + }; + + struct InputLayoutCounterPair + { + ID3D11InputLayout *inputLayout; + unsigned long long lastUsedTime; + }; + + ID3D11InputLayout *mCurrentIL; + ID3D11Buffer *mCurrentBuffers[gl::MAX_VERTEX_ATTRIBS]; + UINT mCurrentVertexStrides[gl::MAX_VERTEX_ATTRIBS]; + UINT mCurrentVertexOffsets[gl::MAX_VERTEX_ATTRIBS]; + + static std::size_t hashInputLayout(const InputLayoutKey &inputLayout); + static bool compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b); + + typedef std::size_t (*InputLayoutHashFunction)(const InputLayoutKey &); + typedef bool (*InputLayoutEqualityFunction)(const InputLayoutKey &, const InputLayoutKey &); + typedef std::unordered_map<InputLayoutKey, + InputLayoutCounterPair, + InputLayoutHashFunction, + InputLayoutEqualityFunction> InputLayoutMap; + InputLayoutMap mInputLayoutMap; + + static const unsigned int kMaxInputLayouts; + + unsigned long long mCounter; + + ID3D11Device *mDevice; + ID3D11DeviceContext *mDeviceContext; +}; + +} + +#endif // LIBGLESV2_RENDERER_INPUTLAYOUTCACHE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp new file mode 100644 index 0000000000..07040342c7 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp @@ -0,0 +1,253 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// PixelTransfer11.cpp: +// Implementation for buffer-to-texture and texture-to-buffer copies. +// Used to implement pixel transfers from unpack and to pack buffers. +// + +#include "libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h" +#include "libGLESv2/formatutils.h" +#include "libGLESv2/Texture.h" +#include "libGLESv2/Buffer.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" +#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" +#include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h" +#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" +#include "libGLESv2/Context.h" + +// Precompiled shaders +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexturevs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexturegs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture_4fps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture_4ips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture_4uips.h" + +namespace rx +{ + +PixelTransfer11::PixelTransfer11(Renderer11 *renderer) + : mRenderer(renderer), + mBufferToTextureVS(NULL), + mBufferToTextureGS(NULL), + mParamsConstantBuffer(NULL), + mCopyRasterizerState(NULL), + mCopyDepthStencilState(NULL) +{ + HRESULT result = S_OK; + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RASTERIZER_DESC rasterDesc; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.CullMode = D3D11_CULL_NONE; + rasterDesc.FrontCounterClockwise = FALSE; + rasterDesc.DepthBias = 0; + rasterDesc.SlopeScaledDepthBias = 0.0f; + rasterDesc.DepthBiasClamp = 0.0f; + rasterDesc.DepthClipEnable = TRUE; + rasterDesc.ScissorEnable = FALSE; + rasterDesc.MultisampleEnable = FALSE; + rasterDesc.AntialiasedLineEnable = FALSE; + + result = device->CreateRasterizerState(&rasterDesc, &mCopyRasterizerState); + ASSERT(SUCCEEDED(result)); + + D3D11_DEPTH_STENCIL_DESC depthStencilDesc; + depthStencilDesc.DepthEnable = true; + depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + depthStencilDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.StencilEnable = FALSE; + depthStencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + depthStencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + + result = device->CreateDepthStencilState(&depthStencilDesc, &mCopyDepthStencilState); + ASSERT(SUCCEEDED(result)); + + D3D11_BUFFER_DESC constantBufferDesc = { 0 }; + constantBufferDesc.ByteWidth = rx::roundUp<UINT>(sizeof(CopyShaderParams), 32u); + constantBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constantBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + constantBufferDesc.MiscFlags = 0; + constantBufferDesc.StructureByteStride = 0; + + result = device->CreateBuffer(&constantBufferDesc, NULL, &mParamsConstantBuffer); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mParamsConstantBuffer, "PixelTransfer11 constant buffer"); + + StructZero(&mParamsData); + + // init shaders + if (mRenderer->isLevel9()) + return; + + mBufferToTextureVS = d3d11::CompileVS(device, g_VS_BufferToTexture, "BufferToTexture VS"); + mBufferToTextureGS = d3d11::CompileGS(device, g_GS_BufferToTexture, "BufferToTexture GS"); + + buildShaderMap(); +} + +PixelTransfer11::~PixelTransfer11() +{ + for (auto shaderMapIt = mBufferToTexturePSMap.begin(); shaderMapIt != mBufferToTexturePSMap.end(); shaderMapIt++) + { + SafeRelease(shaderMapIt->second); + } + + mBufferToTexturePSMap.clear(); + + SafeRelease(mBufferToTextureVS); + SafeRelease(mBufferToTextureGS); + SafeRelease(mParamsConstantBuffer); + SafeRelease(mCopyRasterizerState); + SafeRelease(mCopyDepthStencilState); +} + +void PixelTransfer11::setBufferToTextureCopyParams(const gl::Box &destArea, const gl::Extents &destSize, GLenum internalFormat, + const gl::PixelUnpackState &unpack, unsigned int offset, CopyShaderParams *parametersOut) +{ + StructZero(parametersOut); + + float texelCenterX = 0.5f / static_cast<float>(destSize.width - 1); + float texelCenterY = 0.5f / static_cast<float>(destSize.height - 1); + + unsigned int bytesPerPixel = gl::GetPixelBytes(internalFormat); + unsigned int alignmentBytes = static_cast<unsigned int>(unpack.alignment); + unsigned int alignmentPixels = (alignmentBytes <= bytesPerPixel ? 1 : alignmentBytes / bytesPerPixel); + + parametersOut->FirstPixelOffset = offset; + parametersOut->PixelsPerRow = static_cast<unsigned int>(destArea.width); + parametersOut->RowStride = roundUp(parametersOut->PixelsPerRow, alignmentPixels); + parametersOut->RowsPerSlice = static_cast<unsigned int>(destArea.height); + parametersOut->PositionOffset[0] = texelCenterX + (destArea.x / float(destSize.width)) * 2.0f - 1.0f; + parametersOut->PositionOffset[1] = texelCenterY + ((destSize.height - destArea.y - 1) / float(destSize.height)) * 2.0f - 1.0f; + parametersOut->PositionScale[0] = 2.0f / static_cast<float>(destSize.width); + parametersOut->PositionScale[1] = -2.0f / static_cast<float>(destSize.height); +} + +bool PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +{ + gl::Extents destSize = destRenderTarget->getExtents(); + + if (destArea.x < 0 || destArea.x + destArea.width > destSize.width || + destArea.y < 0 || destArea.y + destArea.height > destSize.height || + destArea.z < 0 || destArea.z + destArea.depth > destSize.depth ) + { + return false; + } + + const gl::Buffer &sourceBuffer = *unpack.pixelBuffer.get(); + + ASSERT(mRenderer->supportsFastCopyBufferToTexture(destinationFormat)); + + ID3D11PixelShader *pixelShader = findBufferToTexturePS(destinationFormat); + ASSERT(pixelShader); + + // The SRV must be in the proper read format, which may be different from the destination format + // EG: for half float data, we can load full precision floats with implicit conversion + GLenum unsizedFormat = gl::GetFormat(destinationFormat); + GLenum sourceFormat = gl::GetSizedInternalFormat(unsizedFormat, sourcePixelsType); + + DXGI_FORMAT srvFormat = gl_d3d11::GetSRVFormat(sourceFormat); + ASSERT(srvFormat != DXGI_FORMAT_UNKNOWN); + Buffer11 *bufferStorage11 = Buffer11::makeBuffer11(sourceBuffer.getImplementation()); + ID3D11ShaderResourceView *bufferSRV = bufferStorage11->getSRV(srvFormat); + ASSERT(bufferSRV != NULL); + + ID3D11RenderTargetView *textureRTV = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ASSERT(textureRTV != NULL); + + CopyShaderParams shaderParams; + setBufferToTextureCopyParams(destArea, destSize, sourceFormat, unpack, offset, &shaderParams); + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + ID3D11ShaderResourceView *nullSRV = NULL; + ID3D11Buffer *nullBuffer = NULL; + UINT zero = 0; + + // Are we doing a 2D or 3D copy? + ID3D11GeometryShader *geometryShader = ((destSize.depth > 1) ? mBufferToTextureGS : NULL); + + deviceContext->VSSetShader(mBufferToTextureVS, NULL, 0); + deviceContext->GSSetShader(geometryShader, NULL, 0); + deviceContext->PSSetShader(pixelShader, NULL, 0); + deviceContext->PSSetShaderResources(0, 1, &bufferSRV); + deviceContext->IASetInputLayout(NULL); + deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); + + deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); + deviceContext->OMSetDepthStencilState(mCopyDepthStencilState, 0xFFFFFFFF); + deviceContext->RSSetState(mCopyRasterizerState); + + mRenderer->setOneTimeRenderTarget(textureRTV); + + if (!StructEquals(mParamsData, shaderParams)) + { + d3d11::SetBufferData(deviceContext, mParamsConstantBuffer, shaderParams); + mParamsData = shaderParams; + } + + deviceContext->VSSetConstantBuffers(0, 1, &mParamsConstantBuffer); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = destSize.width; + viewport.Height = destSize.height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + UINT numPixels = (destArea.width * destArea.height * destArea.depth); + deviceContext->Draw(numPixels, 0); + + // Unbind textures and render targets and vertex buffer + deviceContext->PSSetShaderResources(0, 1, &nullSRV); + deviceContext->VSSetConstantBuffers(0, 1, &nullBuffer); + + mRenderer->markAllStateDirty(); + + return true; +} + +void PixelTransfer11::buildShaderMap() +{ + ID3D11Device *device = mRenderer->getDevice(); + + mBufferToTexturePSMap[GL_FLOAT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4F, "BufferToTexture RGBA ps"); + mBufferToTexturePSMap[GL_INT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4I, "BufferToTexture RGBA-I ps"); + mBufferToTexturePSMap[GL_UNSIGNED_INT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4UI, "BufferToTexture RGBA-UI ps"); +} + +ID3D11PixelShader *PixelTransfer11::findBufferToTexturePS(GLenum internalFormat) const +{ + GLenum componentType = gl::GetComponentType(internalFormat); + + if (componentType == GL_SIGNED_NORMALIZED || componentType == GL_UNSIGNED_NORMALIZED) + { + componentType = GL_FLOAT; + } + + auto shaderMapIt = mBufferToTexturePSMap.find(componentType); + return (shaderMapIt == mBufferToTexturePSMap.end() ? NULL : shaderMapIt->second); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h new file mode 100644 index 0000000000..2e2fee8f50 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h @@ -0,0 +1,82 @@ +// +// 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. +// + +// PixelTransfer11.h: +// Buffer-to-Texture and Texture-to-Buffer data transfers. +// Used to implement pixel unpack and pixel pack buffers in ES3. + +#ifndef LIBGLESV2_PIXELTRANSFER11_H_ +#define LIBGLESV2_PIXELTRANSFER11_H_ + +#include "common/platform.h" + +namespace gl +{ + +class Buffer; +struct Box; +struct Extents; +struct PixelUnpackState; + +} + +namespace rx +{ +class Renderer11; +class RenderTarget; + +class PixelTransfer11 +{ + public: + explicit PixelTransfer11(Renderer11 *renderer); + ~PixelTransfer11(); + + static bool supportsBufferToTextureCopy(GLenum internalFormat); + + // unpack: the source buffer is stored in the unpack state, and buffer strides + // offset: the start of the data within the unpack buffer + // destRenderTarget: individual slice/layer of a target texture + // destinationFormat/sourcePixelsType: determines shaders + shader parameters + // destArea: the sub-section of destRenderTarget to copy to + bool copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + + private: + + struct CopyShaderParams + { + unsigned int FirstPixelOffset; + unsigned int PixelsPerRow; + unsigned int RowStride; + unsigned int RowsPerSlice; + float PositionOffset[2]; + float PositionScale[2]; + int TexLocationOffset[2]; + int TexLocationScale[2]; + }; + + static void setBufferToTextureCopyParams(const gl::Box &destArea, const gl::Extents &destSize, GLenum internalFormat, + const gl::PixelUnpackState &unpack, unsigned int offset, CopyShaderParams *parametersOut); + + void buildShaderMap(); + ID3D11PixelShader *findBufferToTexturePS(GLenum internalFormat) const; + + Renderer11 *mRenderer; + + std::map<GLenum, ID3D11PixelShader *> mBufferToTexturePSMap; + ID3D11VertexShader *mBufferToTextureVS; + ID3D11GeometryShader *mBufferToTextureGS; + ID3D11Buffer *mParamsConstantBuffer; + CopyShaderParams mParamsData; + + ID3D11RasterizerState *mCopyRasterizerState; + ID3D11DepthStencilState *mCopyDepthStencilState; + +}; + +} + +#endif // LIBGLESV2_PIXELTRANSFER11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp new file mode 100644 index 0000000000..e5e00325b2 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp @@ -0,0 +1,163 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Query11.cpp: Defines the rx::Query11 class which implements rx::QueryImpl. + +#include "libGLESv2/renderer/d3d/d3d11/Query11.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/main.h" + +#if defined(__MINGW32__) // Provide undefined struct +typedef struct D3D11_QUERY_DATA_SO_STATISTICS +{ + UINT64 NumPrimitivesWritten; + UINT64 PrimitivesStorageNeeded; +} D3D11_QUERY_DATA_SO_STATISTICS; +#endif + +namespace rx +{ + +static bool checkOcclusionQuery(ID3D11DeviceContext *context, ID3D11Query *query, UINT64 *numPixels) +{ + HRESULT result = context->GetData(query, numPixels, sizeof(UINT64), 0); + return (result == S_OK); +} + +static bool checkStreamOutPrimitivesWritten(ID3D11DeviceContext *context, ID3D11Query *query, UINT64 *numPrimitives) +{ + D3D11_QUERY_DATA_SO_STATISTICS soStats = { 0 }; + HRESULT result = context->GetData(query, &soStats, sizeof(D3D11_QUERY_DATA_SO_STATISTICS), 0); + *numPrimitives = soStats.NumPrimitivesWritten; + return (result == S_OK); +} + +Query11::Query11(rx::Renderer11 *renderer, GLenum type) : QueryImpl(type) +{ + mRenderer = renderer; + mQuery = NULL; +} + +Query11::~Query11() +{ + SafeRelease(mQuery); +} + +void Query11::begin() +{ + if (mQuery == NULL) + { + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = gl_d3d11::ConvertQueryType(getType()); + queryDesc.MiscFlags = 0; + + if (FAILED(mRenderer->getDevice()->CreateQuery(&queryDesc, &mQuery))) + { + return gl::error(GL_OUT_OF_MEMORY); + } + } + + mRenderer->getDeviceContext()->Begin(mQuery); +} + +void Query11::end() +{ + ASSERT(mQuery); + mRenderer->getDeviceContext()->End(mQuery); + + mStatus = GL_FALSE; + mResult = GL_FALSE; +} + +GLuint Query11::getResult() +{ + if (mQuery != NULL) + { + while (!testQuery()) + { + Sleep(0); + // explicitly check for device loss, some drivers seem to return S_FALSE + // if the device is lost + if (mRenderer->testDeviceLost(true)) + { + return gl::error(GL_OUT_OF_MEMORY, 0); + } + } + } + + return mResult; +} + +GLboolean Query11::isResultAvailable() +{ + if (mQuery != NULL) + { + testQuery(); + } + + return mStatus; +} + +GLboolean Query11::testQuery() +{ + if (mQuery != NULL && mStatus != GL_TRUE) + { + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + bool queryFinished = false; + switch (getType()) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + { + UINT64 numPixels = 0; + queryFinished = checkOcclusionQuery(context, mQuery, &numPixels); + if (queryFinished) + { + mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + } + } + break; + + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: + { + UINT64 numPrimitives = 0; + queryFinished = checkStreamOutPrimitivesWritten(context, mQuery, &numPrimitives); + if (queryFinished) + { + mResult = static_cast<GLuint>(numPrimitives); + } + } + break; + + default: + UNREACHABLE(); + break; + } + + if (queryFinished) + { + mStatus = GL_TRUE; + } + else if (mRenderer->testDeviceLost(true)) + { + return gl::error(GL_OUT_OF_MEMORY, GL_TRUE); + } + + return mStatus; + } + + return GL_TRUE; // prevent blocking when query is null +} + +bool Query11::isStarted() const +{ + return (mQuery != NULL); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.h new file mode 100644 index 0000000000..7a3df46d4f --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.h @@ -0,0 +1,41 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Query11.h: Defines the rx::Query11 class which implements rx::QueryImpl. + +#ifndef LIBGLESV2_RENDERER_QUERY11_H_ +#define LIBGLESV2_RENDERER_QUERY11_H_ + +#include "libGLESv2/renderer/QueryImpl.h" + +namespace rx +{ +class Renderer11; + +class Query11 : public QueryImpl +{ + public: + Query11(rx::Renderer11 *renderer, GLenum type); + virtual ~Query11(); + + virtual void begin(); + virtual void end(); + virtual GLuint getResult(); + virtual GLboolean isResultAvailable(); + virtual bool isStarted() const; + + private: + DISALLOW_COPY_AND_ASSIGN(Query11); + + GLboolean testQuery(); + + rx::Renderer11 *mRenderer; + ID3D11Query *mQuery; +}; + +} + +#endif // LIBGLESV2_RENDERER_QUERY11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.cpp new file mode 100644 index 0000000000..b185d97604 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.cpp @@ -0,0 +1,436 @@ +#include "precompiled.h" +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderStateCache.cpp: Defines rx::RenderStateCache, a cache of Direct3D render +// state objects. + +#include "libGLESv2/renderer/d3d/d3d11/RenderStateCache.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" + +#include "common/debug.h" +#include "third_party/murmurhash/MurmurHash3.h" + +namespace rx +{ + +template <typename mapType> +static void ClearStateMap(mapType &map) +{ + for (typename mapType::iterator i = map.begin(); i != map.end(); i++) + { + SafeRelease(i->second.first); + } + map.clear(); +} + +// MSDN's documentation of ID3D11Device::CreateBlendState, ID3D11Device::CreateRasterizerState, +// ID3D11Device::CreateDepthStencilState and ID3D11Device::CreateSamplerState claims the maximum +// number of unique states of each type an application can create is 4096 +const unsigned int RenderStateCache::kMaxBlendStates = 4096; +const unsigned int RenderStateCache::kMaxRasterizerStates = 4096; +const unsigned int RenderStateCache::kMaxDepthStencilStates = 4096; +const unsigned int RenderStateCache::kMaxSamplerStates = 4096; + +RenderStateCache::RenderStateCache() : mDevice(NULL), mCounter(0), + mBlendStateCache(kMaxBlendStates, hashBlendState, compareBlendStates), + mRasterizerStateCache(kMaxRasterizerStates, hashRasterizerState, compareRasterizerStates), + mDepthStencilStateCache(kMaxDepthStencilStates, hashDepthStencilState, compareDepthStencilStates), + mSamplerStateCache(kMaxSamplerStates, hashSamplerState, compareSamplerStates) +{ +} + +RenderStateCache::~RenderStateCache() +{ + clear(); +} + +void RenderStateCache::initialize(ID3D11Device *device) +{ + clear(); + mDevice = device; +} + +void RenderStateCache::clear() +{ + ClearStateMap(mBlendStateCache); + ClearStateMap(mRasterizerStateCache); + ClearStateMap(mDepthStencilStateCache); + ClearStateMap(mSamplerStateCache); +} + +std::size_t RenderStateCache::hashBlendState(const BlendStateKey &blendState) +{ + static const unsigned int seed = 0xABCDEF98; + + std::size_t hash = 0; + MurmurHash3_x86_32(&blendState, sizeof(gl::BlendState), seed, &hash); + return hash; +} + +bool RenderStateCache::compareBlendStates(const BlendStateKey &a, const BlendStateKey &b) +{ + return memcmp(&a, &b, sizeof(BlendStateKey)) == 0; +} + +ID3D11BlendState *RenderStateCache::getBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState) +{ + if (!mDevice) + { + ERR("RenderStateCache is not initialized."); + return NULL; + } + + bool mrt = false; + + BlendStateKey key = { 0 }; + key.blendState = blendState; + for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + const gl::FramebufferAttachment *attachment = framebuffer->getColorbuffer(i); + if (attachment) + { + if (i > 0) + { + mrt = true; + } + + key.rtChannels[i][0] = attachment->getRedSize() > 0; + key.rtChannels[i][1] = attachment->getGreenSize() > 0; + key.rtChannels[i][2] = attachment->getBlueSize() > 0; + key.rtChannels[i][3] = attachment->getAlphaSize() > 0; + } + else + { + key.rtChannels[i][0] = false; + key.rtChannels[i][1] = false; + key.rtChannels[i][2] = false; + key.rtChannels[i][3] = false; + } + } + + BlendStateMap::iterator keyIter = mBlendStateCache.find(key); + if (keyIter != mBlendStateCache.end()) + { + BlendStateCounterPair &state = keyIter->second; + state.second = mCounter++; + return state.first; + } + else + { + if (mBlendStateCache.size() >= kMaxBlendStates) + { + TRACE("Overflowed the limit of %u blend states, removing the least recently used " + "to make room.", kMaxBlendStates); + + BlendStateMap::iterator leastRecentlyUsed = mBlendStateCache.begin(); + for (BlendStateMap::iterator i = mBlendStateCache.begin(); i != mBlendStateCache.end(); i++) + { + if (i->second.second < leastRecentlyUsed->second.second) + { + leastRecentlyUsed = i; + } + } + SafeRelease(leastRecentlyUsed->second.first); + mBlendStateCache.erase(leastRecentlyUsed); + } + + // Create a new blend state and insert it into the cache + D3D11_BLEND_DESC blendDesc = { 0 }; + blendDesc.AlphaToCoverageEnable = blendState.sampleAlphaToCoverage; + blendDesc.IndependentBlendEnable = mrt ? TRUE : FALSE; + + for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + D3D11_RENDER_TARGET_BLEND_DESC &rtBlend = blendDesc.RenderTarget[i]; + + rtBlend.BlendEnable = blendState.blend; + if (blendState.blend) + { + rtBlend.SrcBlend = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendRGB, false); + rtBlend.DestBlend = gl_d3d11::ConvertBlendFunc(blendState.destBlendRGB, false); + rtBlend.BlendOp = gl_d3d11::ConvertBlendOp(blendState.blendEquationRGB); + + rtBlend.SrcBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendAlpha, true); + rtBlend.DestBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.destBlendAlpha, true); + rtBlend.BlendOpAlpha = gl_d3d11::ConvertBlendOp(blendState.blendEquationAlpha); + } + + rtBlend.RenderTargetWriteMask = gl_d3d11::ConvertColorMask(key.rtChannels[i][0] && blendState.colorMaskRed, + key.rtChannels[i][1] && blendState.colorMaskGreen, + key.rtChannels[i][2] && blendState.colorMaskBlue, + key.rtChannels[i][3] && blendState.colorMaskAlpha); + } + + ID3D11BlendState *dx11BlendState = NULL; + HRESULT result = mDevice->CreateBlendState(&blendDesc, &dx11BlendState); + if (FAILED(result) || !dx11BlendState) + { + ERR("Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result); + return NULL; + } + + mBlendStateCache.insert(std::make_pair(key, std::make_pair(dx11BlendState, mCounter++))); + + return dx11BlendState; + } +} + +std::size_t RenderStateCache::hashRasterizerState(const RasterizerStateKey &rasterState) +{ + static const unsigned int seed = 0xABCDEF98; + + std::size_t hash = 0; + MurmurHash3_x86_32(&rasterState, sizeof(RasterizerStateKey), seed, &hash); + return hash; +} + +bool RenderStateCache::compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b) +{ + return memcmp(&a, &b, sizeof(RasterizerStateKey)) == 0; +} + +ID3D11RasterizerState *RenderStateCache::getRasterizerState(const gl::RasterizerState &rasterState, bool scissorEnabled) +{ + if (!mDevice) + { + ERR("RenderStateCache is not initialized."); + return NULL; + } + + RasterizerStateKey key = { 0 }; + key.rasterizerState = rasterState; + key.scissorEnabled = scissorEnabled; + + RasterizerStateMap::iterator keyIter = mRasterizerStateCache.find(key); + if (keyIter != mRasterizerStateCache.end()) + { + RasterizerStateCounterPair &state = keyIter->second; + state.second = mCounter++; + return state.first; + } + else + { + if (mRasterizerStateCache.size() >= kMaxRasterizerStates) + { + TRACE("Overflowed the limit of %u rasterizer states, removing the least recently used " + "to make room.", kMaxRasterizerStates); + + RasterizerStateMap::iterator leastRecentlyUsed = mRasterizerStateCache.begin(); + for (RasterizerStateMap::iterator i = mRasterizerStateCache.begin(); i != mRasterizerStateCache.end(); i++) + { + if (i->second.second < leastRecentlyUsed->second.second) + { + leastRecentlyUsed = i; + } + } + SafeRelease(leastRecentlyUsed->second.first); + mRasterizerStateCache.erase(leastRecentlyUsed); + } + + D3D11_CULL_MODE cullMode = gl_d3d11::ConvertCullMode(rasterState.cullFace, rasterState.cullMode); + + // Disable culling if drawing points + if (rasterState.pointDrawMode) + { + cullMode = D3D11_CULL_NONE; + } + + D3D11_RASTERIZER_DESC rasterDesc; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.CullMode = cullMode; + rasterDesc.FrontCounterClockwise = (rasterState.frontFace == GL_CCW) ? FALSE: TRUE; + rasterDesc.DepthBiasClamp = 0.0f; // MSDN documentation of DepthBiasClamp implies a value of zero will preform no clamping, must be tested though. + rasterDesc.DepthClipEnable = TRUE; + rasterDesc.ScissorEnable = scissorEnabled ? TRUE : FALSE; + rasterDesc.MultisampleEnable = rasterState.multiSample; + rasterDesc.AntialiasedLineEnable = FALSE; + + if (rasterState.polygonOffsetFill) + { + rasterDesc.SlopeScaledDepthBias = rasterState.polygonOffsetFactor; + rasterDesc.DepthBias = (INT)rasterState.polygonOffsetUnits; + } + else + { + rasterDesc.SlopeScaledDepthBias = 0.0f; + rasterDesc.DepthBias = 0; + } + + ID3D11RasterizerState *dx11RasterizerState = NULL; + HRESULT result = mDevice->CreateRasterizerState(&rasterDesc, &dx11RasterizerState); + if (FAILED(result) || !dx11RasterizerState) + { + ERR("Unable to create a ID3D11RasterizerState, HRESULT: 0x%X.", result); + return NULL; + } + + mRasterizerStateCache.insert(std::make_pair(key, std::make_pair(dx11RasterizerState, mCounter++))); + + return dx11RasterizerState; + } +} + +std::size_t RenderStateCache::hashDepthStencilState(const gl::DepthStencilState &dsState) +{ + static const unsigned int seed = 0xABCDEF98; + + std::size_t hash = 0; + MurmurHash3_x86_32(&dsState, sizeof(gl::DepthStencilState), seed, &hash); + return hash; +} + +bool RenderStateCache::compareDepthStencilStates(const gl::DepthStencilState &a, const gl::DepthStencilState &b) +{ + return memcmp(&a, &b, sizeof(gl::DepthStencilState)) == 0; +} + +ID3D11DepthStencilState *RenderStateCache::getDepthStencilState(const gl::DepthStencilState &dsState) +{ + if (!mDevice) + { + ERR("RenderStateCache is not initialized."); + return NULL; + } + + DepthStencilStateMap::iterator keyIter = mDepthStencilStateCache.find(dsState); + if (keyIter != mDepthStencilStateCache.end()) + { + DepthStencilStateCounterPair &state = keyIter->second; + state.second = mCounter++; + return state.first; + } + else + { + if (mDepthStencilStateCache.size() >= kMaxDepthStencilStates) + { + TRACE("Overflowed the limit of %u depth stencil states, removing the least recently used " + "to make room.", kMaxDepthStencilStates); + + DepthStencilStateMap::iterator leastRecentlyUsed = mDepthStencilStateCache.begin(); + for (DepthStencilStateMap::iterator i = mDepthStencilStateCache.begin(); i != mDepthStencilStateCache.end(); i++) + { + if (i->second.second < leastRecentlyUsed->second.second) + { + leastRecentlyUsed = i; + } + } + SafeRelease(leastRecentlyUsed->second.first); + mDepthStencilStateCache.erase(leastRecentlyUsed); + } + + D3D11_DEPTH_STENCIL_DESC dsDesc = { 0 }; + dsDesc.DepthEnable = dsState.depthTest ? TRUE : FALSE; + dsDesc.DepthWriteMask = gl_d3d11::ConvertDepthMask(dsState.depthMask); + dsDesc.DepthFunc = gl_d3d11::ConvertComparison(dsState.depthFunc); + dsDesc.StencilEnable = dsState.stencilTest ? TRUE : FALSE; + dsDesc.StencilReadMask = gl_d3d11::ConvertStencilMask(dsState.stencilMask); + dsDesc.StencilWriteMask = gl_d3d11::ConvertStencilMask(dsState.stencilWritemask); + dsDesc.FrontFace.StencilFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilFail); + dsDesc.FrontFace.StencilDepthFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilPassDepthFail); + dsDesc.FrontFace.StencilPassOp = gl_d3d11::ConvertStencilOp(dsState.stencilPassDepthPass); + dsDesc.FrontFace.StencilFunc = gl_d3d11::ConvertComparison(dsState.stencilFunc); + dsDesc.BackFace.StencilFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackFail); + dsDesc.BackFace.StencilDepthFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackPassDepthFail); + dsDesc.BackFace.StencilPassOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackPassDepthPass); + dsDesc.BackFace.StencilFunc = gl_d3d11::ConvertComparison(dsState.stencilBackFunc); + + ID3D11DepthStencilState *dx11DepthStencilState = NULL; + HRESULT result = mDevice->CreateDepthStencilState(&dsDesc, &dx11DepthStencilState); + if (FAILED(result) || !dx11DepthStencilState) + { + ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result); + return NULL; + } + + mDepthStencilStateCache.insert(std::make_pair(dsState, std::make_pair(dx11DepthStencilState, mCounter++))); + + return dx11DepthStencilState; + } +} + +std::size_t RenderStateCache::hashSamplerState(const gl::SamplerState &samplerState) +{ + static const unsigned int seed = 0xABCDEF98; + + std::size_t hash = 0; + MurmurHash3_x86_32(&samplerState, sizeof(gl::SamplerState), seed, &hash); + return hash; +} + +bool RenderStateCache::compareSamplerStates(const gl::SamplerState &a, const gl::SamplerState &b) +{ + return memcmp(&a, &b, sizeof(gl::SamplerState)) == 0; +} + +ID3D11SamplerState *RenderStateCache::getSamplerState(const gl::SamplerState &samplerState) +{ + if (!mDevice) + { + ERR("RenderStateCache is not initialized."); + return NULL; + } + + SamplerStateMap::iterator keyIter = mSamplerStateCache.find(samplerState); + if (keyIter != mSamplerStateCache.end()) + { + SamplerStateCounterPair &state = keyIter->second; + state.second = mCounter++; + return state.first; + } + else + { + if (mSamplerStateCache.size() >= kMaxSamplerStates) + { + TRACE("Overflowed the limit of %u sampler states, removing the least recently used " + "to make room.", kMaxSamplerStates); + + SamplerStateMap::iterator leastRecentlyUsed = mSamplerStateCache.begin(); + for (SamplerStateMap::iterator i = mSamplerStateCache.begin(); i != mSamplerStateCache.end(); i++) + { + if (i->second.second < leastRecentlyUsed->second.second) + { + leastRecentlyUsed = i; + } + } + SafeRelease(leastRecentlyUsed->second.first); + mSamplerStateCache.erase(leastRecentlyUsed); + } + + D3D11_SAMPLER_DESC samplerDesc; + samplerDesc.Filter = gl_d3d11::ConvertFilter(samplerState.minFilter, samplerState.magFilter, + samplerState.maxAnisotropy, samplerState.compareMode); + samplerDesc.AddressU = gl_d3d11::ConvertTextureWrap(samplerState.wrapS); + samplerDesc.AddressV = gl_d3d11::ConvertTextureWrap(samplerState.wrapT); + samplerDesc.AddressW = gl_d3d11::ConvertTextureWrap(samplerState.wrapR); + samplerDesc.MipLODBias = 0; + samplerDesc.MaxAnisotropy = samplerState.maxAnisotropy; + samplerDesc.ComparisonFunc = gl_d3d11::ConvertComparison(samplerState.compareFunc); + samplerDesc.BorderColor[0] = 0.0f; + samplerDesc.BorderColor[1] = 0.0f; + samplerDesc.BorderColor[2] = 0.0f; + samplerDesc.BorderColor[3] = 0.0f; + samplerDesc.MinLOD = samplerState.minLod; + samplerDesc.MaxLOD = samplerState.maxLod; + + ID3D11SamplerState *dx11SamplerState = NULL; + HRESULT result = mDevice->CreateSamplerState(&samplerDesc, &dx11SamplerState); + if (FAILED(result) || !dx11SamplerState) + { + ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result); + return NULL; + } + + mSamplerStateCache.insert(std::make_pair(samplerState, std::make_pair(dx11SamplerState, mCounter++))); + + return dx11SamplerState; + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.h new file mode 100644 index 0000000000..e6380fbd82 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.h @@ -0,0 +1,109 @@ +// +// 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. +// + +// RenderStateCache.h: Defines rx::RenderStateCache, a cache of Direct3D render +// state objects. + +#ifndef LIBGLESV2_RENDERER_RENDERSTATECACHE_H_ +#define LIBGLESV2_RENDERER_RENDERSTATECACHE_H_ + +#include "libGLESv2/angletypes.h" +#include "common/angleutils.h" + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ +class Renderer11; + +class RenderStateCache +{ + public: + RenderStateCache(); + virtual ~RenderStateCache(); + + void initialize(ID3D11Device *device); + void clear(); + + ID3D11BlendState *getBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState); + ID3D11RasterizerState *getRasterizerState(const gl::RasterizerState &rasterState, bool scissorEnabled); + ID3D11DepthStencilState *getDepthStencilState(const gl::DepthStencilState &dsState); + ID3D11SamplerState *getSamplerState(const gl::SamplerState &samplerState); + + private: + DISALLOW_COPY_AND_ASSIGN(RenderStateCache); + + unsigned long long mCounter; + + // Blend state cache + struct BlendStateKey + { + gl::BlendState blendState; + bool rtChannels[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT][4]; + }; + static std::size_t hashBlendState(const BlendStateKey &blendState); + static bool compareBlendStates(const BlendStateKey &a, const BlendStateKey &b); + static const unsigned int kMaxBlendStates; + + typedef std::size_t (*BlendStateHashFunction)(const BlendStateKey &); + typedef bool (*BlendStateEqualityFunction)(const BlendStateKey &, const BlendStateKey &); + typedef std::pair<ID3D11BlendState*, unsigned long long> BlendStateCounterPair; + typedef std::unordered_map<BlendStateKey, BlendStateCounterPair, BlendStateHashFunction, BlendStateEqualityFunction> BlendStateMap; + BlendStateMap mBlendStateCache; + + // Rasterizer state cache + struct RasterizerStateKey + { + gl::RasterizerState rasterizerState; + bool scissorEnabled; + }; + static std::size_t hashRasterizerState(const RasterizerStateKey &rasterState); + static bool compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b); + static const unsigned int kMaxRasterizerStates; + + typedef std::size_t (*RasterizerStateHashFunction)(const RasterizerStateKey &); + typedef bool (*RasterizerStateEqualityFunction)(const RasterizerStateKey &, const RasterizerStateKey &); + typedef std::pair<ID3D11RasterizerState*, unsigned long long> RasterizerStateCounterPair; + typedef std::unordered_map<RasterizerStateKey, RasterizerStateCounterPair, RasterizerStateHashFunction, RasterizerStateEqualityFunction> RasterizerStateMap; + RasterizerStateMap mRasterizerStateCache; + + // Depth stencil state cache + static std::size_t hashDepthStencilState(const gl::DepthStencilState &dsState); + static bool compareDepthStencilStates(const gl::DepthStencilState &a, const gl::DepthStencilState &b); + static const unsigned int kMaxDepthStencilStates; + + typedef std::size_t (*DepthStencilStateHashFunction)(const gl::DepthStencilState &); + typedef bool (*DepthStencilStateEqualityFunction)(const gl::DepthStencilState &, const gl::DepthStencilState &); + typedef std::pair<ID3D11DepthStencilState*, unsigned long long> DepthStencilStateCounterPair; + typedef std::unordered_map<gl::DepthStencilState, + DepthStencilStateCounterPair, + DepthStencilStateHashFunction, + DepthStencilStateEqualityFunction> DepthStencilStateMap; + DepthStencilStateMap mDepthStencilStateCache; + + // Sample state cache + static std::size_t hashSamplerState(const gl::SamplerState &samplerState); + static bool compareSamplerStates(const gl::SamplerState &a, const gl::SamplerState &b); + static const unsigned int kMaxSamplerStates; + + typedef std::size_t (*SamplerStateHashFunction)(const gl::SamplerState &); + typedef bool (*SamplerStateEqualityFunction)(const gl::SamplerState &, const gl::SamplerState &); + typedef std::pair<ID3D11SamplerState*, unsigned long long> SamplerStateCounterPair; + typedef std::unordered_map<gl::SamplerState, + SamplerStateCounterPair, + SamplerStateHashFunction, + SamplerStateEqualityFunction> SamplerStateMap; + SamplerStateMap mSamplerStateCache; + + ID3D11Device *mDevice; +}; + +} + +#endif // LIBGLESV2_RENDERER_RENDERSTATECACHE_H_
\ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.cpp new file mode 100644 index 0000000000..6aa75ae5bd --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.cpp @@ -0,0 +1,457 @@ +#include "precompiled.h" +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderTarget11.cpp: Implements a DX11-specific wrapper for ID3D11View pointers +// retained by Renderbuffers. + +#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" + +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" +#include "libGLESv2/main.h" + +namespace rx +{ + +static bool getTextureProperties(ID3D11Resource *resource, unsigned int *mipLevels, unsigned int *samples) +{ + ID3D11Texture1D *texture1D = d3d11::DynamicCastComObject<ID3D11Texture1D>(resource); + if (texture1D) + { + D3D11_TEXTURE1D_DESC texDesc; + texture1D->GetDesc(&texDesc); + SafeRelease(texture1D); + + *mipLevels = texDesc.MipLevels; + *samples = 0; + + return true; + } + + ID3D11Texture2D *texture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(resource); + if (texture2D) + { + D3D11_TEXTURE2D_DESC texDesc; + texture2D->GetDesc(&texDesc); + SafeRelease(texture2D); + + *mipLevels = texDesc.MipLevels; + *samples = texDesc.SampleDesc.Count > 1 ? texDesc.SampleDesc.Count : 0; + + return true; + } + + ID3D11Texture3D *texture3D = d3d11::DynamicCastComObject<ID3D11Texture3D>(resource); + if (texture3D) + { + D3D11_TEXTURE3D_DESC texDesc; + texture3D->GetDesc(&texDesc); + SafeRelease(texture3D); + + *mipLevels = texDesc.MipLevels; + *samples = 0; + + return true; + } + + return false; +} + +static unsigned int getRTVSubresourceIndex(ID3D11Resource *resource, ID3D11RenderTargetView *view) +{ + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + view->GetDesc(&rtvDesc); + + unsigned int mipSlice = 0; + unsigned int arraySlice = 0; + + switch (rtvDesc.ViewDimension) + { + case D3D11_RTV_DIMENSION_TEXTURE1D: + mipSlice = rtvDesc.Texture1D.MipSlice; + arraySlice = 0; + break; + + case D3D11_RTV_DIMENSION_TEXTURE1DARRAY: + mipSlice = rtvDesc.Texture1DArray.MipSlice; + arraySlice = rtvDesc.Texture1DArray.FirstArraySlice; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2D: + mipSlice = rtvDesc.Texture2D.MipSlice; + arraySlice = 0; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DARRAY: + mipSlice = rtvDesc.Texture2DArray.MipSlice; + arraySlice = rtvDesc.Texture2DArray.FirstArraySlice; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMS: + mipSlice = 0; + arraySlice = 0; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY: + mipSlice = 0; + arraySlice = rtvDesc.Texture2DMSArray.FirstArraySlice; + break; + + case D3D11_RTV_DIMENSION_TEXTURE3D: + mipSlice = rtvDesc.Texture3D.MipSlice; + arraySlice = 0; + break; + + case D3D11_RTV_DIMENSION_UNKNOWN: + case D3D11_RTV_DIMENSION_BUFFER: + UNIMPLEMENTED(); + break; + + default: + UNREACHABLE(); + break; + } + + unsigned int mipLevels, samples; + getTextureProperties(resource, &mipLevels, &samples); + + return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels); +} + +static unsigned int getDSVSubresourceIndex(ID3D11Resource *resource, ID3D11DepthStencilView *view) +{ + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + view->GetDesc(&dsvDesc); + + unsigned int mipSlice = 0; + unsigned int arraySlice = 0; + + switch (dsvDesc.ViewDimension) + { + case D3D11_DSV_DIMENSION_TEXTURE1D: + mipSlice = dsvDesc.Texture1D.MipSlice; + arraySlice = 0; + break; + + case D3D11_DSV_DIMENSION_TEXTURE1DARRAY: + mipSlice = dsvDesc.Texture1DArray.MipSlice; + arraySlice = dsvDesc.Texture1DArray.FirstArraySlice; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2D: + mipSlice = dsvDesc.Texture2D.MipSlice; + arraySlice = 0; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DARRAY: + mipSlice = dsvDesc.Texture2DArray.MipSlice; + arraySlice = dsvDesc.Texture2DArray.FirstArraySlice; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DMS: + mipSlice = 0; + arraySlice = 0; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY: + mipSlice = 0; + arraySlice = dsvDesc.Texture2DMSArray.FirstArraySlice; + break; + + case D3D11_DSV_DIMENSION_UNKNOWN: + UNIMPLEMENTED(); + break; + + default: + UNREACHABLE(); + break; + } + + unsigned int mipLevels, samples; + getTextureProperties(resource, &mipLevels, &samples); + + return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels); +} + +RenderTarget11::RenderTarget11(Renderer *renderer, ID3D11RenderTargetView *rtv, ID3D11Resource *resource, + ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth) +{ + mRenderer = Renderer11::makeRenderer11(renderer); + + mTexture = resource; + if (mTexture) + { + mTexture->AddRef(); + } + + mRenderTarget = rtv; + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + mDepthStencil = NULL; + + mShaderResource = srv; + if (mShaderResource) + { + mShaderResource->AddRef(); + } + + mSubresourceIndex = 0; + + if (mRenderTarget && mTexture) + { + D3D11_RENDER_TARGET_VIEW_DESC desc; + mRenderTarget->GetDesc(&desc); + + unsigned int mipLevels, samples; + getTextureProperties(mTexture, &mipLevels, &samples); + + mSubresourceIndex = getRTVSubresourceIndex(mTexture, mRenderTarget); + mWidth = width; + mHeight = height; + mDepth = depth; + mSamples = samples; + + mInternalFormat = d3d11_gl::GetInternalFormat(desc.Format); + mActualFormat = d3d11_gl::GetInternalFormat(desc.Format); + } +} + +RenderTarget11::RenderTarget11(Renderer *renderer, ID3D11DepthStencilView *dsv, ID3D11Resource *resource, + ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth) +{ + mRenderer = Renderer11::makeRenderer11(renderer); + + mTexture = resource; + if (mTexture) + { + mTexture->AddRef(); + } + + mRenderTarget = NULL; + + mDepthStencil = dsv; + if (mDepthStencil) + { + mDepthStencil->AddRef(); + } + + mShaderResource = srv; + if (mShaderResource) + { + mShaderResource->AddRef(); + } + + mSubresourceIndex = 0; + + if (mDepthStencil && mTexture) + { + D3D11_DEPTH_STENCIL_VIEW_DESC desc; + mDepthStencil->GetDesc(&desc); + + unsigned int mipLevels, samples; + getTextureProperties(mTexture, &mipLevels, &samples); + + mSubresourceIndex = getDSVSubresourceIndex(mTexture, mDepthStencil); + mWidth = width; + mHeight = height; + mDepth = depth; + mSamples = samples; + + mInternalFormat = d3d11_gl::GetInternalFormat(desc.Format); + mActualFormat = d3d11_gl::GetInternalFormat(desc.Format); + } +} + +RenderTarget11::RenderTarget11(Renderer *renderer, GLsizei width, GLsizei height, GLenum internalFormat, GLsizei samples) +{ + mRenderer = Renderer11::makeRenderer11(renderer); + mTexture = NULL; + mRenderTarget = NULL; + mDepthStencil = NULL; + mShaderResource = NULL; + + DXGI_FORMAT texFormat = gl_d3d11::GetTexFormat(internalFormat); + DXGI_FORMAT srvFormat = gl_d3d11::GetSRVFormat(internalFormat); + DXGI_FORMAT rtvFormat = gl_d3d11::GetRTVFormat(internalFormat); + DXGI_FORMAT dsvFormat = gl_d3d11::GetDSVFormat(internalFormat); + + DXGI_FORMAT multisampleFormat = (dsvFormat != DXGI_FORMAT_UNKNOWN ? dsvFormat : rtvFormat); + int supportedSamples = mRenderer->getNearestSupportedSamples(multisampleFormat, samples); + if (supportedSamples < 0) + { + gl::error(GL_OUT_OF_MEMORY); + return; + } + + if (width > 0 && height > 0) + { + // Create texture resource + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = texFormat; + desc.SampleDesc.Count = (supportedSamples == 0) ? 1 : supportedSamples; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + // If a rendertarget or depthstencil format exists for this texture format, + // we'll flag it to allow binding that way. Shader resource views are a little + // more complicated. + bool bindRTV = false, bindDSV = false, bindSRV = false; + bindRTV = (rtvFormat != DXGI_FORMAT_UNKNOWN); + bindDSV = (dsvFormat != DXGI_FORMAT_UNKNOWN); + if (srvFormat != DXGI_FORMAT_UNKNOWN) + { + // Multisample targets flagged for binding as depth stencil cannot also be + // flagged for binding as SRV, so make certain not to add the SRV flag for + // these targets. + bindSRV = !(dsvFormat != DXGI_FORMAT_UNKNOWN && desc.SampleDesc.Count > 1); + } + + desc.BindFlags = (bindRTV ? D3D11_BIND_RENDER_TARGET : 0) | + (bindDSV ? D3D11_BIND_DEPTH_STENCIL : 0) | + (bindSRV ? D3D11_BIND_SHADER_RESOURCE : 0); + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11Texture2D *texture = NULL; + HRESULT result = device->CreateTexture2D(&desc, NULL, &texture); + mTexture = texture; + + if (result == E_OUTOFMEMORY) + { + gl::error(GL_OUT_OF_MEMORY); + return; + } + ASSERT(SUCCEEDED(result)); + + if (bindSRV) + { + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = srvFormat; + srvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS; + srvDesc.Texture2D.MostDetailedMip = 0; + srvDesc.Texture2D.MipLevels = 1; + result = device->CreateShaderResourceView(mTexture, &srvDesc, &mShaderResource); + + if (result == E_OUTOFMEMORY) + { + SafeRelease(mTexture); + gl::error(GL_OUT_OF_MEMORY); + return; + } + ASSERT(SUCCEEDED(result)); + } + + if (bindDSV) + { + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = dsvFormat; + dsvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_DSV_DIMENSION_TEXTURE2D : D3D11_DSV_DIMENSION_TEXTURE2DMS; + dsvDesc.Texture2D.MipSlice = 0; + dsvDesc.Flags = 0; + result = device->CreateDepthStencilView(mTexture, &dsvDesc, &mDepthStencil); + + if (result == E_OUTOFMEMORY) + { + SafeRelease(mTexture); + SafeRelease(mShaderResource); + gl::error(GL_OUT_OF_MEMORY); + return; + } + ASSERT(SUCCEEDED(result)); + } + + if (bindRTV) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = rtvFormat; + rtvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_RTV_DIMENSION_TEXTURE2D : D3D11_RTV_DIMENSION_TEXTURE2DMS; + rtvDesc.Texture2D.MipSlice = 0; + result = device->CreateRenderTargetView(mTexture, &rtvDesc, &mRenderTarget); + + if (result == E_OUTOFMEMORY) + { + SafeRelease(mTexture); + SafeRelease(mShaderResource); + SafeRelease(mDepthStencil); + gl::error(GL_OUT_OF_MEMORY); + return; + } + ASSERT(SUCCEEDED(result)); + + if (gl_d3d11::RequiresTextureDataInitialization(internalFormat)) + { + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + const float clearValues[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + context->ClearRenderTargetView(mRenderTarget, clearValues); + } + } + } + + mWidth = width; + mHeight = height; + mDepth = 1; + mInternalFormat = internalFormat; + mSamples = supportedSamples; + mActualFormat = d3d11_gl::GetInternalFormat(texFormat); + mSubresourceIndex = D3D11CalcSubresource(0, 0, 1); +} + +RenderTarget11::~RenderTarget11() +{ + SafeRelease(mTexture); + SafeRelease(mRenderTarget); + SafeRelease(mDepthStencil); + SafeRelease(mShaderResource); +} + +RenderTarget11 *RenderTarget11::makeRenderTarget11(RenderTarget *target) +{ + ASSERT(HAS_DYNAMIC_TYPE(rx::RenderTarget11*, target)); + return static_cast<rx::RenderTarget11*>(target); +} + +void RenderTarget11::invalidate(GLint x, GLint y, GLsizei width, GLsizei height) +{ + // Currently a no-op +} + +ID3D11Resource *RenderTarget11::getTexture() const +{ + return mTexture; +} + +ID3D11RenderTargetView *RenderTarget11::getRenderTargetView() const +{ + return mRenderTarget; +} + +ID3D11DepthStencilView *RenderTarget11::getDepthStencilView() const +{ + return mDepthStencil; +} + +ID3D11ShaderResourceView *RenderTarget11::getShaderResourceView() const +{ + return mShaderResource; +} + +unsigned int RenderTarget11::getSubresourceIndex() const +{ + return mSubresourceIndex; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h new file mode 100644 index 0000000000..82182957af --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h @@ -0,0 +1,54 @@ +// +// 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. +// + +// RenderTarget11.h: Defines a DX11-specific wrapper for ID3D11View pointers +// retained by Renderbuffers. + +#ifndef LIBGLESV2_RENDERER_RENDERTARGET11_H_ +#define LIBGLESV2_RENDERER_RENDERTARGET11_H_ + +#include "libGLESv2/renderer/RenderTarget.h" + +namespace rx +{ +class Renderer; +class Renderer11; + +class RenderTarget11 : public RenderTarget +{ + public: + // RenderTarget11 takes ownership of any D3D11 resources it is given and will AddRef them + RenderTarget11(Renderer *renderer, ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth); + RenderTarget11(Renderer *renderer, ID3D11DepthStencilView *dsv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth); + RenderTarget11(Renderer *renderer, GLsizei width, GLsizei height, GLenum internalFormat, GLsizei samples); + virtual ~RenderTarget11(); + + static RenderTarget11 *makeRenderTarget11(RenderTarget *renderTarget); + + virtual void invalidate(GLint x, GLint y, GLsizei width, GLsizei height); + + ID3D11Resource *getTexture() const; + ID3D11RenderTargetView *getRenderTargetView() const; + ID3D11DepthStencilView *getDepthStencilView() const; + ID3D11ShaderResourceView *getShaderResourceView() const; + + unsigned int getSubresourceIndex() const; + + private: + DISALLOW_COPY_AND_ASSIGN(RenderTarget11); + + unsigned int mSubresourceIndex; + ID3D11Resource *mTexture; + ID3D11RenderTargetView *mRenderTarget; + ID3D11DepthStencilView *mDepthStencil; + ID3D11ShaderResourceView *mShaderResource; + + Renderer11 *mRenderer; +}; + +} + +#endif // LIBGLESV2_RENDERER_RENDERTARGET11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp new file mode 100644 index 0000000000..3ba0cc767b --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp @@ -0,0 +1,3565 @@ +#include "precompiled.h" +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Renderer11.cpp: Implements a back-end specific class for the D3D11 renderer. + +#include "libGLESv2/main.h" +#include "common/utilities.h" +#include "common/platform.h" +#include "libGLESv2/Buffer.h" +#include "libGLESv2/FramebufferAttachment.h" +#include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/renderer/d3d/TextureD3D.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" +#include "libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h" +#include "libGLESv2/renderer/d3d/d3d11/SwapChain11.h" +#include "libGLESv2/renderer/d3d/d3d11/Image11.h" +#include "libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h" +#include "libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h" +#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" +#include "libGLESv2/renderer/d3d/VertexDataManager.h" +#include "libGLESv2/renderer/d3d/IndexDataManager.h" +#include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h" +#include "libGLESv2/renderer/d3d/d3d11/Query11.h" +#include "libGLESv2/renderer/d3d/d3d11/Fence11.h" +#include "libGLESv2/renderer/d3d/d3d11/Blit11.h" +#include "libGLESv2/renderer/d3d/d3d11/Clear11.h" +#include "libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h" +#include "libGLESv2/renderer/d3d/d3d11/VertexArray11.h" +#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" +#include "libEGL/Display.h" + +// Enable ANGLE_SKIP_DXGI_1_2_CHECK if there is not a possibility of using cross-process +// HWNDs or the Windows 7 Platform Update (KB2670838) is expected to be installed. +#ifndef ANGLE_SKIP_DXGI_1_2_CHECK +#define ANGLE_SKIP_DXGI_1_2_CHECK 0 +#endif + +#ifdef _DEBUG +// this flag enables suppressing some spurious warnings that pop up in certain WebGL samples +// and conformance tests. to enable all warnings, remove this define. +#define ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS 1 +#endif + +#ifndef D3D11_PS_INPUT_REGISTER_COUNT +# define D3D11_PS_INPUT_REGISTER_COUNT 32 +#endif +#ifndef D3D10_1_VS_OUTPUT_REGISTER_COUNT +# define D3D10_1_VS_OUTPUT_REGISTER_COUNT 32 +#endif +#ifndef D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT +# define D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT 14 +#endif +#ifndef D3D11_SO_BUFFER_SLOT_COUNT +# define D3D11_SO_BUFFER_SLOT_COUNT 4 +#endif +#ifndef D3D10_1_SO_BUFFER_SLOT_COUNT +# define D3D10_1_SO_BUFFER_SLOT_COUNT 4 +#endif +#ifndef D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT +# define D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT 4096 +#endif +#ifndef D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP +# define D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP 32 +#endif +#ifndef D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP +# define D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP 32 +#endif + +namespace rx +{ +static const DXGI_FORMAT RenderTargetFormats[] = + { + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM + }; + +static const DXGI_FORMAT DepthStencilFormats[] = + { + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_D16_UNORM + }; + +enum +{ + MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 = 16 +}; + +Renderer11::Renderer11(egl::Display *display, EGLNativeDisplayType hDc, EGLint requestedDisplay) + : Renderer(display), + mDc(hDc), + mRequestedDisplay(requestedDisplay) +{ + mVertexDataManager = NULL; + mIndexDataManager = NULL; + + mLineLoopIB = NULL; + mTriangleFanIB = NULL; + + mBlit = NULL; + mPixelTransfer = NULL; + + mClear = NULL; + + mSyncQuery = NULL; + + mD3d11Module = NULL; + mDxgiModule = NULL; + + mDeviceLost = false; + + mMaxSupportedSamples = 0; + + mDevice = NULL; + mDeviceContext = NULL; + mDxgiAdapter = NULL; + mDxgiFactory = NULL; + + mDriverConstantBufferVS = NULL; + mDriverConstantBufferPS = NULL; + + mAppliedVertexShader = NULL; + mAppliedGeometryShader = NULL; + mCurPointGeometryShader = NULL; + mAppliedPixelShader = NULL; +} + +Renderer11::~Renderer11() +{ + release(); +} + +Renderer11 *Renderer11::makeRenderer11(Renderer *renderer) +{ + ASSERT(HAS_DYNAMIC_TYPE(rx::Renderer11*, renderer)); + return static_cast<rx::Renderer11*>(renderer); +} + +#ifndef __d3d11_1_h__ +#define D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET ((D3D11_MESSAGE_ID)3146081) +#endif + +EGLint Renderer11::initialize() +{ + if (!mCompiler.initialize()) + { + return EGL_NOT_INITIALIZED; + } + +#if !defined(ANGLE_PLATFORM_WINRT) + mDxgiModule = LoadLibrary(TEXT("dxgi.dll")); + mD3d11Module = LoadLibrary(TEXT("d3d11.dll")); + + if (mD3d11Module == NULL || mDxgiModule == NULL) + { + ERR("Could not load D3D11 or DXGI library - aborting!\n"); + return EGL_NOT_INITIALIZED; + } + + // create the D3D11 device + ASSERT(mDevice == NULL); + PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); + + if (D3D11CreateDevice == NULL) + { + ERR("Could not retrieve D3D11CreateDevice address - aborting!\n"); + return EGL_NOT_INITIALIZED; + } +#endif + + D3D_FEATURE_LEVEL featureLevels[] = + { + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, +#if !defined(ANGLE_ENABLE_D3D9) + D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1, +#endif + }; + + D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_HARDWARE; + if (mRequestedDisplay == EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE) + { + driverType = D3D_DRIVER_TYPE_WARP; + } + + HRESULT result = S_OK; + +#ifdef _DEBUG + result = D3D11CreateDevice(NULL, + driverType, + NULL, + D3D11_CREATE_DEVICE_DEBUG, + featureLevels, + ArraySize(featureLevels), + D3D11_SDK_VERSION, + &mDevice, + &mFeatureLevel, + &mDeviceContext); + + if (!mDevice || FAILED(result)) + { + ERR("Failed creating Debug D3D11 device - falling back to release runtime.\n"); + } + + if (!mDevice || FAILED(result)) +#endif + { + result = D3D11CreateDevice(NULL, + driverType, + NULL, + 0, + featureLevels, + ArraySize(featureLevels), + D3D11_SDK_VERSION, + &mDevice, + &mFeatureLevel, + &mDeviceContext); + + if (!mDevice || FAILED(result)) + { + ERR("Could not create D3D11 device - aborting!\n"); + return EGL_NOT_INITIALIZED; // Cleanup done by destructor through glDestroyRenderer + } + } + +#if !ANGLE_SKIP_DXGI_1_2_CHECK && !defined(ANGLE_PLATFORM_WINRT) + // In order to create a swap chain for an HWND owned by another process, DXGI 1.2 is required. + // The easiest way to check is to query for a IDXGIDevice2. + bool requireDXGI1_2 = false; + HWND hwnd = WindowFromDC(mDc); + if (hwnd) + { + DWORD currentProcessId = GetCurrentProcessId(); + DWORD wndProcessId; + GetWindowThreadProcessId(hwnd, &wndProcessId); + requireDXGI1_2 = (currentProcessId != wndProcessId); + } + else + { + requireDXGI1_2 = true; + } + + if (requireDXGI1_2) + { + IDXGIDevice2 *dxgiDevice2 = NULL; + result = mDevice->QueryInterface(__uuidof(IDXGIDevice2), (void**)&dxgiDevice2); + if (FAILED(result)) + { + ERR("DXGI 1.2 required to present to HWNDs owned by another process.\n"); + return EGL_NOT_INITIALIZED; + } + SafeRelease(dxgiDevice2); + } +#endif + +#if !defined(ANGLE_PLATFORM_WINRT) + IDXGIDevice *dxgiDevice = NULL; +#else + IDXGIDevice1 *dxgiDevice = NULL; +#endif + result = mDevice->QueryInterface(IID_PPV_ARGS(&dxgiDevice)); + + if (FAILED(result)) + { + ERR("Could not query DXGI device - aborting!\n"); + return EGL_NOT_INITIALIZED; + } + + result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&mDxgiAdapter); + + if (FAILED(result)) + { + ERR("Could not retrieve DXGI adapter - aborting!\n"); + return EGL_NOT_INITIALIZED; + } + + SafeRelease(dxgiDevice); + + mDxgiAdapter->GetDesc(&mAdapterDescription); + memset(mDescription, 0, sizeof(mDescription)); + wcstombs(mDescription, mAdapterDescription.Description, sizeof(mDescription) - 1); + + result = mDxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&mDxgiFactory); + + if (!mDxgiFactory || FAILED(result)) + { + ERR("Could not create DXGI factory - aborting!\n"); + return EGL_NOT_INITIALIZED; + } + + // Disable some spurious D3D11 debug warnings to prevent them from flooding the output log +#if !defined(__MINGW32__) && defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG) + ID3D11InfoQueue *infoQueue; + result = mDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)&infoQueue); + + if (SUCCEEDED(result)) + { + D3D11_MESSAGE_ID hideMessages[] = + { + D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET + }; + + D3D11_INFO_QUEUE_FILTER filter = {0}; + filter.DenyList.NumIDs = ArraySize(hideMessages); + filter.DenyList.pIDList = hideMessages; + + infoQueue->AddStorageFilterEntries(&filter); + SafeRelease(infoQueue); + } +#endif + + mMaxSupportedSamples = 0; + + const d3d11::DXGIFormatSet &dxgiFormats = d3d11::GetAllUsedDXGIFormats(); + for (d3d11::DXGIFormatSet::const_iterator i = dxgiFormats.begin(); i != dxgiFormats.end(); ++i) + { + MultisampleSupportInfo support = getMultisampleSupportInfo(*i); + mMultisampleSupportMap.insert(std::make_pair(*i, support)); + mMaxSupportedSamples = std::max(mMaxSupportedSamples, support.maxSupportedSamples); + } + +#if !defined(ANGLE_PLATFORM_WINRT) + static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED"); + if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1")) + { + ID3D10Multithread *multithread; + result = mDevice->QueryInterface(IID_PPV_ARGS(&multithread)); + ASSERT(SUCCEEDED(result)); + result = multithread->SetMultithreadProtected(true); + ASSERT(SUCCEEDED(result)); + multithread->Release(); + } +#endif + + initializeDevice(); + + return EGL_SUCCESS; +} + +// do any one-time device initialization +// NOTE: this is also needed after a device lost/reset +// to reset the scene status and ensure the default states are reset. +void Renderer11::initializeDevice() +{ + mStateCache.initialize(mDevice); + mInputLayoutCache.initialize(mDevice, mDeviceContext); + + ASSERT(!mVertexDataManager && !mIndexDataManager); + mVertexDataManager = new VertexDataManager(this); + mIndexDataManager = new IndexDataManager(this); + + ASSERT(!mBlit); + mBlit = new Blit11(this); + + ASSERT(!mClear); + mClear = new Clear11(this); + + ASSERT(!mPixelTransfer); + mPixelTransfer = new PixelTransfer11(this); + + markAllStateDirty(); +} + +int Renderer11::generateConfigs(ConfigDesc **configDescList) +{ + unsigned int numRenderFormats = ArraySize(RenderTargetFormats); + unsigned int numDepthFormats = ArraySize(DepthStencilFormats); + (*configDescList) = new ConfigDesc[numRenderFormats * numDepthFormats]; + int numConfigs = 0; + + for (unsigned int formatIndex = 0; formatIndex < numRenderFormats; formatIndex++) + { + for (unsigned int depthStencilIndex = 0; depthStencilIndex < numDepthFormats; depthStencilIndex++) + { + DXGI_FORMAT renderTargetFormat = RenderTargetFormats[formatIndex]; + + UINT formatSupport = 0; + HRESULT result = mDevice->CheckFormatSupport(renderTargetFormat, &formatSupport); + + if (SUCCEEDED(result) && (formatSupport & D3D11_FORMAT_SUPPORT_RENDER_TARGET)) + { + DXGI_FORMAT depthStencilFormat = DepthStencilFormats[depthStencilIndex]; + + bool depthStencilFormatOK = true; + + if (depthStencilFormat != DXGI_FORMAT_UNKNOWN) + { + UINT depthStencilSupport = 0; + result = mDevice->CheckFormatSupport(depthStencilFormat, &depthStencilSupport); + depthStencilFormatOK = SUCCEEDED(result) && (depthStencilSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL); + } + + if (depthStencilFormatOK) + { + ConfigDesc newConfig; + newConfig.renderTargetFormat = d3d11_gl::GetInternalFormat(renderTargetFormat); + newConfig.depthStencilFormat = d3d11_gl::GetInternalFormat(depthStencilFormat); + newConfig.multiSample = 0; // FIXME: enumerate multi-sampling + newConfig.fastConfig = true; // Assume all DX11 format conversions to be fast + newConfig.es3Capable = true; + + (*configDescList)[numConfigs++] = newConfig; + } + } + } + } + + return numConfigs; +} + +void Renderer11::deleteConfigs(ConfigDesc *configDescList) +{ + delete [] (configDescList); +} + +void Renderer11::sync(bool block) +{ + if (block) + { + HRESULT result; + + if (!mSyncQuery) + { + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = D3D11_QUERY_EVENT; + queryDesc.MiscFlags = 0; + + result = mDevice->CreateQuery(&queryDesc, &mSyncQuery); + ASSERT(SUCCEEDED(result)); + } + + mDeviceContext->End(mSyncQuery); + mDeviceContext->Flush(); + + do + { + result = mDeviceContext->GetData(mSyncQuery, NULL, 0, D3D11_ASYNC_GETDATA_DONOTFLUSH); + + // Keep polling, but allow other threads to do something useful first + Sleep(0); + + if (testDeviceLost(true)) + { + return; + } + } + while (result == S_FALSE); + } + else + { + mDeviceContext->Flush(); + } +} + +SwapChain *Renderer11::createSwapChain(EGLNativeWindowType window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) +{ + return new rx::SwapChain11(this, window, shareHandle, backBufferFormat, depthBufferFormat); +} + +void Renderer11::generateSwizzle(gl::Texture *texture) +{ + if (texture) + { + TextureStorageInterface *texStorage = texture->getNativeTexture(); + if (texStorage) + { + TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage->getStorageInstance()); + + storage11->generateSwizzles(texture->getSamplerState().swizzleRed, + texture->getSamplerState().swizzleGreen, + texture->getSamplerState().swizzleBlue, + texture->getSamplerState().swizzleAlpha); + } + } +} + +void Renderer11::setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &samplerState) +{ + if (type == gl::SAMPLER_PIXEL) + { + if (index < 0 || index >= gl::MAX_TEXTURE_IMAGE_UNITS) + { + ERR("Pixel shader sampler index %i is not valid.", index); + return; + } + + if (mForceSetPixelSamplerStates[index] || memcmp(&samplerState, &mCurPixelSamplerStates[index], sizeof(gl::SamplerState)) != 0) + { + ID3D11SamplerState *dxSamplerState = mStateCache.getSamplerState(samplerState); + + if (!dxSamplerState) + { + ERR("NULL sampler state returned by RenderStateCache::getSamplerState, setting the default" + "sampler state for pixel shaders at slot %i.", index); + } + + mDeviceContext->PSSetSamplers(index, 1, &dxSamplerState); + + mCurPixelSamplerStates[index] = samplerState; + } + + mForceSetPixelSamplerStates[index] = false; + } + else if (type == gl::SAMPLER_VERTEX) + { + if (index < 0 || index >= (int)getMaxVertexTextureImageUnits()) + { + ERR("Vertex shader sampler index %i is not valid.", index); + return; + } + + if (mForceSetVertexSamplerStates[index] || memcmp(&samplerState, &mCurVertexSamplerStates[index], sizeof(gl::SamplerState)) != 0) + { + ID3D11SamplerState *dxSamplerState = mStateCache.getSamplerState(samplerState); + + if (!dxSamplerState) + { + ERR("NULL sampler state returned by RenderStateCache::getSamplerState, setting the default" + "sampler state for vertex shaders at slot %i.", index); + } + + mDeviceContext->VSSetSamplers(index, 1, &dxSamplerState); + + mCurVertexSamplerStates[index] = samplerState; + } + + mForceSetVertexSamplerStates[index] = false; + } + else UNREACHABLE(); +} + +void Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *texture) +{ + ID3D11ShaderResourceView *textureSRV = NULL; + bool forceSetTexture = false; + + if (texture) + { + TextureStorageInterface *texStorage = texture->getNativeTexture(); + if (texStorage) + { + TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage->getStorageInstance()); + gl::SamplerState samplerState; + texture->getSamplerStateWithNativeOffset(&samplerState); + textureSRV = storage11->getSRV(samplerState); + } + + // If we get NULL back from getSRV here, something went wrong in the texture class and we're unexpectedly + // missing the shader resource view + ASSERT(textureSRV != NULL); + + forceSetTexture = texture->hasDirtyImages(); + } + + if (type == gl::SAMPLER_PIXEL) + { + if (index < 0 || index >= gl::MAX_TEXTURE_IMAGE_UNITS) + { + ERR("Pixel shader sampler index %i is not valid.", index); + return; + } + + if (forceSetTexture || mCurPixelSRVs[index] != textureSRV) + { + mDeviceContext->PSSetShaderResources(index, 1, &textureSRV); + } + + mCurPixelSRVs[index] = textureSRV; + } + else if (type == gl::SAMPLER_VERTEX) + { + if (index < 0 || index >= (int)getMaxVertexTextureImageUnits()) + { + ERR("Vertex shader sampler index %i is not valid.", index); + return; + } + + if (forceSetTexture || mCurVertexSRVs[index] != textureSRV) + { + mDeviceContext->VSSetShaderResources(index, 1, &textureSRV); + } + + mCurVertexSRVs[index] = textureSRV; + } + else UNREACHABLE(); +} + +bool Renderer11::setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]) +{ + for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; uniformBufferIndex++) + { + const gl::Buffer *uniformBuffer = vertexUniformBuffers[uniformBufferIndex]; + if (uniformBuffer) + { + Buffer11 *bufferStorage = Buffer11::makeBuffer11(uniformBuffer->getImplementation()); + ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); + + if (!constantBuffer) + { + return false; + } + + if (mCurrentConstantBufferVS[uniformBufferIndex] != bufferStorage->getSerial()) + { + mDeviceContext->VSSetConstantBuffers(getReservedVertexUniformBuffers() + uniformBufferIndex, + 1, &constantBuffer); + mCurrentConstantBufferVS[uniformBufferIndex] = bufferStorage->getSerial(); + } + } + } + + for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS; uniformBufferIndex++) + { + const gl::Buffer *uniformBuffer = fragmentUniformBuffers[uniformBufferIndex]; + if (uniformBuffer) + { + Buffer11 *bufferStorage = Buffer11::makeBuffer11(uniformBuffer->getImplementation()); + ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); + + if (!constantBuffer) + { + return false; + } + + if (mCurrentConstantBufferPS[uniformBufferIndex] != bufferStorage->getSerial()) + { + mDeviceContext->PSSetConstantBuffers(getReservedFragmentUniformBuffers() + uniformBufferIndex, + 1, &constantBuffer); + mCurrentConstantBufferPS[uniformBufferIndex] = bufferStorage->getSerial(); + } + } + } + + return true; +} + +void Renderer11::setRasterizerState(const gl::RasterizerState &rasterState) +{ + if (mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0) + { + ID3D11RasterizerState *dxRasterState = mStateCache.getRasterizerState(rasterState, mScissorEnabled); + if (!dxRasterState) + { + ERR("NULL rasterizer state returned by RenderStateCache::getRasterizerState, setting the default" + "rasterizer state."); + } + + mDeviceContext->RSSetState(dxRasterState); + + mCurRasterState = rasterState; + } + + mForceSetRasterState = false; +} + +void Renderer11::setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask) +{ + if (mForceSetBlendState || + memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0 || + memcmp(&blendColor, &mCurBlendColor, sizeof(gl::ColorF)) != 0 || + sampleMask != mCurSampleMask) + { + ID3D11BlendState *dxBlendState = mStateCache.getBlendState(framebuffer, blendState); + if (!dxBlendState) + { + ERR("NULL blend state returned by RenderStateCache::getBlendState, setting the default " + "blend state."); + } + + float blendColors[4] = {0.0f}; + 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) + { + blendColors[0] = blendColor.red; + blendColors[1] = blendColor.green; + blendColors[2] = blendColor.blue; + blendColors[3] = blendColor.alpha; + } + else + { + blendColors[0] = blendColor.alpha; + blendColors[1] = blendColor.alpha; + blendColors[2] = blendColor.alpha; + blendColors[3] = blendColor.alpha; + } + + mDeviceContext->OMSetBlendState(dxBlendState, blendColors, sampleMask); + + mCurBlendState = blendState; + mCurBlendColor = blendColor; + mCurSampleMask = sampleMask; + } + + mForceSetBlendState = false; +} + +void Renderer11::setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, + int stencilBackRef, bool frontFaceCCW) +{ + if (mForceSetDepthStencilState || + memcmp(&depthStencilState, &mCurDepthStencilState, sizeof(gl::DepthStencilState)) != 0 || + stencilRef != mCurStencilRef || stencilBackRef != mCurStencilBackRef) + { + ASSERT(depthStencilState.stencilWritemask == depthStencilState.stencilBackWritemask); + ASSERT(stencilRef == stencilBackRef); + ASSERT(depthStencilState.stencilMask == depthStencilState.stencilBackMask); + + ID3D11DepthStencilState *dxDepthStencilState = mStateCache.getDepthStencilState(depthStencilState); + if (!dxDepthStencilState) + { + ERR("NULL depth stencil state returned by RenderStateCache::getDepthStencilState, " + "setting the default depth stencil state."); + } + + // Max D3D11 stencil reference value is 0xFF, corresponding to the max 8 bits in a stencil buffer + // GL specifies we should clamp the ref value to the nearest bit depth when doing stencil ops + META_ASSERT(D3D11_DEFAULT_STENCIL_READ_MASK == 0xFF); + META_ASSERT(D3D11_DEFAULT_STENCIL_WRITE_MASK == 0xFF); + UINT dxStencilRef = std::min<UINT>(stencilRef, 0xFFu); + + mDeviceContext->OMSetDepthStencilState(dxDepthStencilState, dxStencilRef); + + mCurDepthStencilState = depthStencilState; + mCurStencilRef = stencilRef; + mCurStencilBackRef = stencilBackRef; + } + + mForceSetDepthStencilState = false; +} + +void Renderer11::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) +{ + if (mForceSetScissor || memcmp(&scissor, &mCurScissor, sizeof(gl::Rectangle)) != 0 || + enabled != mScissorEnabled) + { + if (enabled) + { + D3D11_RECT rect; + rect.left = std::max(0, scissor.x); + rect.top = std::max(0, scissor.y); + rect.right = scissor.x + std::max(0, scissor.width); + rect.bottom = scissor.y + std::max(0, scissor.height); + + mDeviceContext->RSSetScissorRects(1, &rect); + } + + if (enabled != mScissorEnabled) + { + mForceSetRasterState = true; + } + + mCurScissor = scissor; + mScissorEnabled = enabled; + } + + mForceSetScissor = false; +} + +bool Renderer11::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, + bool ignoreViewport) +{ + gl::Rectangle actualViewport = viewport; + float actualZNear = gl::clamp01(zNear); + float actualZFar = gl::clamp01(zFar); + if (ignoreViewport) + { + actualViewport.x = 0; + actualViewport.y = 0; + actualViewport.width = mRenderTargetDesc.width; + actualViewport.height = mRenderTargetDesc.height; + actualZNear = 0.0f; + actualZFar = 1.0f; + } + + const gl::Caps& caps = getRendererCaps(); + + // Clamp width and height first to the gl maximum, then clamp further if we extend past the D3D maximum bounds + D3D11_VIEWPORT dxViewport; + dxViewport.TopLeftX = gl::clamp(actualViewport.x, -static_cast<int>(caps.maxViewportWidth), static_cast<int>(caps.maxViewportWidth)); + dxViewport.TopLeftY = gl::clamp(actualViewport.y, -static_cast<int>(caps.maxViewportHeight), static_cast<int>(caps.maxViewportHeight)); + dxViewport.Width = gl::clamp(actualViewport.width, 0, static_cast<int>(caps.maxViewportWidth - dxViewport.TopLeftX)); + dxViewport.Height = gl::clamp(actualViewport.height, 0, static_cast<int>(caps.maxViewportHeight - dxViewport.TopLeftY)); + dxViewport.MinDepth = actualZNear; + dxViewport.MaxDepth = actualZFar; + + if (dxViewport.Width <= 0 || dxViewport.Height <= 0) + { + return false; // Nothing to render + } + + bool viewportChanged = mForceSetViewport || memcmp(&actualViewport, &mCurViewport, sizeof(gl::Rectangle)) != 0 || + actualZNear != mCurNear || actualZFar != mCurFar; + + if (viewportChanged) + { + mDeviceContext->RSSetViewports(1, &dxViewport); + + mCurViewport = actualViewport; + mCurNear = actualZNear; + mCurFar = actualZFar; + + mPixelConstants.viewCoords[0] = actualViewport.width * 0.5f; + mPixelConstants.viewCoords[1] = actualViewport.height * 0.5f; + mPixelConstants.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f); + mPixelConstants.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f); + + mPixelConstants.depthFront[0] = (actualZFar - actualZNear) * 0.5f; + mPixelConstants.depthFront[1] = (actualZNear + actualZFar) * 0.5f; + + mVertexConstants.depthRange[0] = actualZNear; + mVertexConstants.depthRange[1] = actualZFar; + mVertexConstants.depthRange[2] = actualZFar - actualZNear; + + mPixelConstants.depthRange[0] = actualZNear; + mPixelConstants.depthRange[1] = actualZFar; + mPixelConstants.depthRange[2] = actualZFar - actualZNear; + } + + mForceSetViewport = false; + return true; +} + +bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count) +{ + D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; + + GLsizei minCount = 0; + + switch (mode) + { + case GL_POINTS: primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; minCount = 1; break; + case GL_LINES: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; minCount = 2; break; + case GL_LINE_LOOP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; minCount = 2; break; + case GL_LINE_STRIP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; minCount = 2; break; + case GL_TRIANGLES: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; minCount = 3; break; + case GL_TRIANGLE_STRIP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; minCount = 3; break; + // emulate fans via rewriting index buffer + case GL_TRIANGLE_FAN: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; minCount = 3; break; + default: + UNREACHABLE(); + return false; + } + + if (primitiveTopology != mCurrentPrimitiveTopology) + { + mDeviceContext->IASetPrimitiveTopology(primitiveTopology); + mCurrentPrimitiveTopology = primitiveTopology; + } + + return count >= minCount; +} + +bool Renderer11::applyRenderTarget(gl::Framebuffer *framebuffer) +{ + // Get the color render buffer and serial + // Also extract the render target dimensions and view + unsigned int renderTargetWidth = 0; + unsigned int renderTargetHeight = 0; + GLenum renderTargetFormat = 0; + unsigned int renderTargetSerials[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {0}; + ID3D11RenderTargetView* framebufferRTVs[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {NULL}; + bool missingColorRenderTarget = true; + + for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) + { + const GLenum drawBufferState = framebuffer->getDrawBufferState(colorAttachment); + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(colorAttachment); + + if (colorbuffer && drawBufferState != GL_NONE) + { + // the draw buffer must be either "none", "back" for the default buffer or the same index as this color (in order) + ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment)); + + // check for zero-sized default framebuffer, which is a special case. + // in this case we do not wish to modify any state and just silently return false. + // this will not report any gl error but will cause the calling method to return. + if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) + { + return false; + } + + renderTargetSerials[colorAttachment] = colorbuffer->getSerial(); + + // Extract the render target dimensions and view + RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(colorbuffer->getRenderTarget()); + if (!renderTarget) + { + ERR("render target pointer unexpectedly null."); + return false; + } + + framebufferRTVs[colorAttachment] = renderTarget->getRenderTargetView(); + if (!framebufferRTVs[colorAttachment]) + { + ERR("render target view pointer unexpectedly null."); + return false; + } + + if (missingColorRenderTarget) + { + renderTargetWidth = colorbuffer->getWidth(); + renderTargetHeight = colorbuffer->getHeight(); + renderTargetFormat = colorbuffer->getActualFormat(); + missingColorRenderTarget = false; + } + + // TODO: Detect if this color buffer is already bound as a texture and unbind it first to prevent + // D3D11 warnings. + } + } + + // Get the depth stencil render buffer and serials + gl::FramebufferAttachment *depthStencil = framebuffer->getDepthbuffer(); + unsigned int depthbufferSerial = 0; + unsigned int stencilbufferSerial = 0; + if (depthStencil) + { + depthbufferSerial = depthStencil->getSerial(); + } + else if (framebuffer->getStencilbuffer()) + { + depthStencil = framebuffer->getStencilbuffer(); + stencilbufferSerial = depthStencil->getSerial(); + } + + ID3D11DepthStencilView* framebufferDSV = NULL; + if (depthStencil) + { + RenderTarget11 *depthStencilRenderTarget = RenderTarget11::makeRenderTarget11(depthStencil->getDepthStencil()); + if (!depthStencilRenderTarget) + { + ERR("render target pointer unexpectedly null."); + SafeRelease(framebufferRTVs); + return false; + } + + framebufferDSV = depthStencilRenderTarget->getDepthStencilView(); + if (!framebufferDSV) + { + ERR("depth stencil view pointer unexpectedly null."); + SafeRelease(framebufferRTVs); + return false; + } + + // If there is no render buffer, the width, height and format values come from + // the depth stencil + if (missingColorRenderTarget) + { + renderTargetWidth = depthStencil->getWidth(); + renderTargetHeight = depthStencil->getHeight(); + renderTargetFormat = depthStencil->getActualFormat(); + } + } + + // Apply the render target and depth stencil + if (!mRenderTargetDescInitialized || !mDepthStencilInitialized || + memcmp(renderTargetSerials, mAppliedRenderTargetSerials, sizeof(renderTargetSerials)) != 0 || + depthbufferSerial != mAppliedDepthbufferSerial || + stencilbufferSerial != mAppliedStencilbufferSerial) + { + mDeviceContext->OMSetRenderTargets(getRendererCaps().maxDrawBuffers, framebufferRTVs, framebufferDSV); + + mRenderTargetDesc.width = renderTargetWidth; + mRenderTargetDesc.height = renderTargetHeight; + mRenderTargetDesc.format = renderTargetFormat; + mForceSetViewport = true; + mForceSetScissor = true; + mForceSetBlendState = true; + + if (!mDepthStencilInitialized) + { + mForceSetRasterState = true; + } + + for (unsigned int rtIndex = 0; rtIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; rtIndex++) + { + mAppliedRenderTargetSerials[rtIndex] = renderTargetSerials[rtIndex]; + } + mAppliedDepthbufferSerial = depthbufferSerial; + mAppliedStencilbufferSerial = stencilbufferSerial; + mRenderTargetDescInitialized = true; + mDepthStencilInitialized = true; + } + + invalidateFramebufferSwizzles(framebuffer); + + return true; +} + +GLenum Renderer11::applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], + GLint first, GLsizei count, GLsizei instances) +{ + TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS]; + GLenum err = mVertexDataManager->prepareVertexData(vertexAttributes, currentValues, programBinary, first, count, attributes, instances); + if (err != GL_NO_ERROR) + { + return err; + } + + return mInputLayoutCache.applyVertexBuffers(attributes, programBinary); +} + +GLenum Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) +{ + GLenum err = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo); + + if (err == GL_NO_ERROR) + { + IndexBuffer11* indexBuffer = IndexBuffer11::makeIndexBuffer11(indexInfo->indexBuffer); + + ID3D11Buffer *buffer = NULL; + DXGI_FORMAT bufferFormat = indexBuffer->getIndexFormat(); + + if (indexInfo->storage) + { + Buffer11 *storage = Buffer11::makeBuffer11(indexInfo->storage); + buffer = storage->getBuffer(BUFFER_USAGE_INDEX); + } + else + { + buffer = indexBuffer->getBuffer(); + } + + if (buffer != mAppliedIB || bufferFormat != mAppliedIBFormat || indexInfo->startOffset != mAppliedIBOffset) + { + mDeviceContext->IASetIndexBuffer(buffer, bufferFormat, indexInfo->startOffset); + + mAppliedIB = buffer; + mAppliedIBFormat = bufferFormat; + mAppliedIBOffset = indexInfo->startOffset; + } + } + + return err; +} + +void Renderer11::applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]) +{ + ID3D11Buffer* d3dBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + UINT d3dOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + bool requiresUpdate = false; + for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + { + if (transformFeedbackBuffers[i]) + { + Buffer11 *storage = Buffer11::makeBuffer11(transformFeedbackBuffers[i]->getImplementation()); + ID3D11Buffer *buffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + + d3dBuffers[i] = buffer; + d3dOffsets[i] = (mAppliedTFBuffers[i] != buffer) ? static_cast<UINT>(offsets[i]) : -1; + } + else + { + d3dBuffers[i] = NULL; + d3dOffsets[i] = 0; + } + + if (d3dBuffers[i] != mAppliedTFBuffers[i] || offsets[i] != mAppliedTFOffsets[i]) + { + requiresUpdate = true; + } + } + + if (requiresUpdate) + { + mDeviceContext->SOSetTargets(ArraySize(d3dBuffers), d3dBuffers, d3dOffsets); + for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + { + mAppliedTFBuffers[i] = d3dBuffers[i]; + mAppliedTFOffsets[i] = offsets[i]; + } + } +} + +void Renderer11::drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) +{ + if (mode == GL_POINTS && transformFeedbackActive) + { + // Since point sprites are generated with a geometry shader, too many vertices will + // be written if transform feedback is active. To work around this, draw only the points + // with the stream out shader and no pixel shader to feed the stream out buffers and then + // draw again with the point sprite geometry shader to rasterize the point sprites. + + mDeviceContext->PSSetShader(NULL, NULL, 0); + + if (instances > 0) + { + mDeviceContext->DrawInstanced(count, instances, 0, 0); + } + else + { + mDeviceContext->Draw(count, 0); + } + + mDeviceContext->GSSetShader(mCurPointGeometryShader, NULL, 0); + mDeviceContext->PSSetShader(mAppliedPixelShader, NULL, 0); + + if (instances > 0) + { + mDeviceContext->DrawInstanced(count, instances, 0, 0); + } + else + { + mDeviceContext->Draw(count, 0); + } + + mDeviceContext->GSSetShader(mAppliedGeometryShader, NULL, 0); + } + else if (mode == GL_LINE_LOOP) + { + drawLineLoop(count, GL_NONE, NULL, 0, NULL); + } + else if (mode == GL_TRIANGLE_FAN) + { + drawTriangleFan(count, GL_NONE, NULL, 0, NULL, instances); + } + else if (instances > 0) + { + mDeviceContext->DrawInstanced(count, instances, 0, 0); + } + else + { + mDeviceContext->Draw(count, 0); + } +} + +void Renderer11::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) +{ + if (mode == GL_LINE_LOOP) + { + drawLineLoop(count, type, indices, indexInfo.minIndex, elementArrayBuffer); + } + else if (mode == GL_TRIANGLE_FAN) + { + drawTriangleFan(count, type, indices, indexInfo.minIndex, elementArrayBuffer, instances); + } + else if (instances > 0) + { + mDeviceContext->DrawIndexedInstanced(count, instances, 0, -static_cast<int>(indexInfo.minIndex), 0); + } + else + { + mDeviceContext->DrawIndexed(count, 0, -static_cast<int>(indexInfo.minIndex)); + } +} + +template<typename T> +static void fillLineLoopIndices(GLenum type, GLsizei count, const GLvoid *indices, T *data) +{ + switch (type) + { + case GL_NONE: // Non-indexed draw + for (int i = 0; i < count; i++) + { + data[i] = i; + } + data[count] = 0; + break; + case GL_UNSIGNED_BYTE: + for (int i = 0; i < count; i++) + { + data[i] = static_cast<const GLubyte*>(indices)[i]; + } + data[count] = static_cast<const GLubyte*>(indices)[0]; + break; + case GL_UNSIGNED_SHORT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast<const GLushort*>(indices)[i]; + } + data[count] = static_cast<const GLushort*>(indices)[0]; + break; + case GL_UNSIGNED_INT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast<const GLuint*>(indices)[i]; + } + data[count] = static_cast<const GLuint*>(indices)[0]; + break; + default: UNREACHABLE(); + } +} + +template<typename T> +static void fillTriangleFanIndices(GLenum type, unsigned int numTris, const GLvoid *indices, T *data) +{ + switch (type) + { + case GL_NONE: // Non-indexed draw + for (unsigned int i = 0; i < numTris; i++) + { + data[i*3 + 0] = 0; + data[i*3 + 1] = i + 1; + data[i*3 + 2] = i + 2; + } + break; + case GL_UNSIGNED_BYTE: + for (unsigned int i = 0; i < numTris; i++) + { + data[i*3 + 0] = static_cast<const GLubyte*>(indices)[0]; + data[i*3 + 1] = static_cast<const GLubyte*>(indices)[i + 1]; + data[i*3 + 2] = static_cast<const GLubyte*>(indices)[i + 2]; + } + break; + case GL_UNSIGNED_SHORT: + for (unsigned int i = 0; i < numTris; i++) + { + data[i*3 + 0] = static_cast<const GLushort*>(indices)[0]; + data[i*3 + 1] = static_cast<const GLushort*>(indices)[i + 1]; + data[i*3 + 2] = static_cast<const GLushort*>(indices)[i + 2]; + } + break; + case GL_UNSIGNED_INT: + for (unsigned int i = 0; i < numTris; i++) + { + data[i*3 + 0] = static_cast<const GLuint*>(indices)[0]; + data[i*3 + 1] = static_cast<const GLuint*>(indices)[i + 1]; + data[i*3 + 2] = static_cast<const GLuint*>(indices)[i + 2]; + } + break; + default: UNREACHABLE(); + } +} + +void Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) +{ + // Get the raw indices for an indexed draw + if (type != GL_NONE && elementArrayBuffer) + { + gl::Buffer *indexBuffer = elementArrayBuffer; + BufferImpl *storage = indexBuffer->getImplementation(); + intptr_t offset = reinterpret_cast<intptr_t>(indices); + indices = static_cast<const GLubyte*>(storage->getData()) + offset; + } + + // TODO: some level 9 hardware supports 32-bit indices; test and store support instead + const int indexType = isLevel9() ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; + + if (!mLineLoopIB) + { + mLineLoopIB = new StreamingIndexBufferInterface(this); + if (!mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, indexType)) + { + delete mLineLoopIB; + mLineLoopIB = NULL; + + ERR("Could not create a 32-bit looping index buffer for GL_LINE_LOOP."); + return gl::error(GL_OUT_OF_MEMORY); + } + } + + // Checked by Renderer11::applyPrimitiveType + ASSERT(count >= 0); + + int indexTypeSize = indexType == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int); + if (static_cast<unsigned int>(count) + 1 > (std::numeric_limits<unsigned int>::max() / indexTypeSize)) + { + ERR("Could not create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); + return gl::error(GL_OUT_OF_MEMORY); + } + + const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * indexTypeSize; + if (!mLineLoopIB->reserveBufferSpace(spaceNeeded, indexType)) + { + ERR("Could not reserve enough space in looping index buffer for GL_LINE_LOOP."); + return gl::error(GL_OUT_OF_MEMORY); + } + + void* mappedMemory = NULL; + unsigned int offset; + if (!mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset)) + { + ERR("Could not map index buffer for GL_LINE_LOOP."); + return gl::error(GL_OUT_OF_MEMORY); + } + + if (indexType == GL_UNSIGNED_SHORT) + fillLineLoopIndices(type, count, indices, reinterpret_cast<unsigned short*>(mappedMemory)); + else + fillLineLoopIndices(type, count, indices, reinterpret_cast<unsigned int*>(mappedMemory)); + unsigned int indexBufferOffset = offset; + + if (!mLineLoopIB->unmapBuffer()) + { + ERR("Could not unmap index buffer for GL_LINE_LOOP."); + return gl::error(GL_OUT_OF_MEMORY); + } + + IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mLineLoopIB->getIndexBuffer()); + ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); + DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); + + if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || mAppliedIBOffset != indexBufferOffset) + { + mDeviceContext->IASetIndexBuffer(indexBuffer->getBuffer(), indexBuffer->getIndexFormat(), indexBufferOffset); + mAppliedIB = d3dIndexBuffer; + mAppliedIBFormat = indexFormat; + mAppliedIBOffset = indexBufferOffset; + } + + mDeviceContext->DrawIndexed(count + 1, 0, -minIndex); +} + +void Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances) +{ + // Get the raw indices for an indexed draw + if (type != GL_NONE && elementArrayBuffer) + { + gl::Buffer *indexBuffer = elementArrayBuffer; + BufferImpl *storage = indexBuffer->getImplementation(); + intptr_t offset = reinterpret_cast<intptr_t>(indices); + indices = static_cast<const GLubyte*>(storage->getData()) + offset; + } + + const int indexType = isLevel9() ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; + + if (!mTriangleFanIB) + { + mTriangleFanIB = new StreamingIndexBufferInterface(this); + if (!mTriangleFanIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, indexType)) + { + delete mTriangleFanIB; + mTriangleFanIB = NULL; + + ERR("Could not create a scratch index buffer for GL_TRIANGLE_FAN."); + return gl::error(GL_OUT_OF_MEMORY); + } + } + + // Checked by Renderer11::applyPrimitiveType + ASSERT(count >= 3); + + const unsigned int numTris = count - 2; + + int indexTypeSize = indexType == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int); + if (numTris > (std::numeric_limits<unsigned int>::max() / (indexTypeSize * 3))) + { + ERR("Could not create a scratch index buffer for GL_TRIANGLE_FAN, too many indices required."); + return gl::error(GL_OUT_OF_MEMORY); + } + + const unsigned int spaceNeeded = (numTris * 3) * indexTypeSize; + if (!mTriangleFanIB->reserveBufferSpace(spaceNeeded, indexType)) + { + ERR("Could not reserve enough space in scratch index buffer for GL_TRIANGLE_FAN."); + return gl::error(GL_OUT_OF_MEMORY); + } + + void* mappedMemory = NULL; + unsigned int offset; + if (!mTriangleFanIB->mapBuffer(spaceNeeded, &mappedMemory, &offset)) + { + ERR("Could not map scratch index buffer for GL_TRIANGLE_FAN."); + return gl::error(GL_OUT_OF_MEMORY); + } + + if (indexType == GL_UNSIGNED_SHORT) + fillTriangleFanIndices(type, numTris, indices, reinterpret_cast<unsigned short*>(mappedMemory)); + else + fillTriangleFanIndices(type, numTris, indices, reinterpret_cast<unsigned int*>(mappedMemory)); + unsigned int indexBufferOffset = offset; + + if (!mTriangleFanIB->unmapBuffer()) + { + ERR("Could not unmap scratch index buffer for GL_TRIANGLE_FAN."); + return gl::error(GL_OUT_OF_MEMORY); + } + + IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mTriangleFanIB->getIndexBuffer()); + ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); + DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); + + if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || mAppliedIBOffset != indexBufferOffset) + { + mDeviceContext->IASetIndexBuffer(indexBuffer->getBuffer(), indexBuffer->getIndexFormat(), indexBufferOffset); + mAppliedIB = d3dIndexBuffer; + mAppliedIBFormat = indexFormat; + mAppliedIBOffset = indexBufferOffset; + } + + if (instances > 0) + { + mDeviceContext->DrawIndexedInstanced(numTris * 3, instances, 0, -minIndex, 0); + } + else + { + mDeviceContext->DrawIndexed(numTris * 3, 0, -minIndex); + } +} + +void Renderer11::applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive) +{ + ShaderExecutable *vertexExe = programBinary->getVertexExecutableForInputLayout(inputLayout); + ShaderExecutable *pixelExe = programBinary->getPixelExecutableForFramebuffer(framebuffer); + ShaderExecutable *geometryExe = programBinary->getGeometryExecutable(); + + ID3D11VertexShader *vertexShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getVertexShader() : NULL); + + ID3D11PixelShader *pixelShader = NULL; + // Skip pixel shader if we're doing rasterizer discard. + if (!rasterizerDiscard) + { + pixelShader = (pixelExe ? ShaderExecutable11::makeShaderExecutable11(pixelExe)->getPixelShader() : NULL); + } + + ID3D11GeometryShader *geometryShader = NULL; + if (transformFeedbackActive) + { + geometryShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getStreamOutShader() : NULL); + } + else if (mCurRasterState.pointDrawMode) + { + geometryShader = (geometryExe ? ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader() : NULL); + } + + bool dirtyUniforms = false; + + if (vertexShader != mAppliedVertexShader) + { + mDeviceContext->VSSetShader(vertexShader, NULL, 0); + mAppliedVertexShader = vertexShader; + dirtyUniforms = true; + } + + if (geometryShader != mAppliedGeometryShader) + { + mDeviceContext->GSSetShader(geometryShader, NULL, 0); + mAppliedGeometryShader = geometryShader; + dirtyUniforms = true; + } + + if (geometryExe && mCurRasterState.pointDrawMode) + { + mCurPointGeometryShader = ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader(); + } + else + { + mCurPointGeometryShader = NULL; + } + + if (pixelShader != mAppliedPixelShader) + { + mDeviceContext->PSSetShader(pixelShader, NULL, 0); + mAppliedPixelShader = pixelShader; + dirtyUniforms = true; + } + + if (dirtyUniforms) + { + programBinary->dirtyAllUniforms(); + } +} + +void Renderer11::applyUniforms(const gl::ProgramBinary &programBinary) +{ + const std::vector<gl::LinkedUniform*> &uniformArray = programBinary.getUniforms(); + + unsigned int totalRegisterCountVS = 0; + unsigned int totalRegisterCountPS = 0; + + bool vertexUniformsDirty = false; + bool pixelUniformsDirty = false; + + for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) + { + const gl::LinkedUniform &uniform = *uniformArray[uniformIndex]; + + if (uniform.isReferencedByVertexShader() && !uniform.isSampler()) + { + totalRegisterCountVS += uniform.registerCount; + vertexUniformsDirty = (vertexUniformsDirty || uniform.dirty); + } + + if (uniform.isReferencedByFragmentShader() && !uniform.isSampler()) + { + totalRegisterCountPS += uniform.registerCount; + pixelUniformsDirty = (pixelUniformsDirty || uniform.dirty); + } + } + + const UniformStorage11 *vertexUniformStorage = UniformStorage11::makeUniformStorage11(&programBinary.getVertexUniformStorage()); + const UniformStorage11 *fragmentUniformStorage = UniformStorage11::makeUniformStorage11(&programBinary.getFragmentUniformStorage()); + ASSERT(vertexUniformStorage); + ASSERT(fragmentUniformStorage); + + ID3D11Buffer *vertexConstantBuffer = vertexUniformStorage->getConstantBuffer(); + ID3D11Buffer *pixelConstantBuffer = fragmentUniformStorage->getConstantBuffer(); + + float (*mapVS)[4] = NULL; + float (*mapPS)[4] = NULL; + + if (totalRegisterCountVS > 0 && vertexUniformsDirty) + { + D3D11_MAPPED_SUBRESOURCE map = {0}; + HRESULT result = mDeviceContext->Map(vertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + mapVS = (float(*)[4])map.pData; + } + + if (totalRegisterCountPS > 0 && pixelUniformsDirty) + { + D3D11_MAPPED_SUBRESOURCE map = {0}; + HRESULT result = mDeviceContext->Map(pixelConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + mapPS = (float(*)[4])map.pData; + } + + for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) + { + gl::LinkedUniform *uniform = uniformArray[uniformIndex]; + + if (!uniform->isSampler()) + { + unsigned int componentCount = (4 - uniform->registerElement); + + // we assume that uniforms from structs are arranged in struct order in our uniforms list. otherwise we would + // overwrite previously written regions of memory. + + if (uniform->isReferencedByVertexShader() && mapVS) + { + memcpy(&mapVS[uniform->vsRegisterIndex][uniform->registerElement], uniform->data, uniform->registerCount * sizeof(float) * componentCount); + } + + if (uniform->isReferencedByFragmentShader() && mapPS) + { + memcpy(&mapPS[uniform->psRegisterIndex][uniform->registerElement], uniform->data, uniform->registerCount * sizeof(float) * componentCount); + } + } + } + + if (mapVS) + { + mDeviceContext->Unmap(vertexConstantBuffer, 0); + } + + if (mapPS) + { + mDeviceContext->Unmap(pixelConstantBuffer, 0); + } + + if (mCurrentVertexConstantBuffer != vertexConstantBuffer) + { + mDeviceContext->VSSetConstantBuffers(0, 1, &vertexConstantBuffer); + mCurrentVertexConstantBuffer = vertexConstantBuffer; + } + + if (mCurrentPixelConstantBuffer != pixelConstantBuffer) + { + mDeviceContext->PSSetConstantBuffers(0, 1, &pixelConstantBuffer); + mCurrentPixelConstantBuffer = pixelConstantBuffer; + } + + // Driver uniforms + if (!mDriverConstantBufferVS) + { + D3D11_BUFFER_DESC constantBufferDescription = {0}; + constantBufferDescription.ByteWidth = sizeof(dx_VertexConstants); + constantBufferDescription.Usage = D3D11_USAGE_DEFAULT; + constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constantBufferDescription.CPUAccessFlags = 0; + constantBufferDescription.MiscFlags = 0; + constantBufferDescription.StructureByteStride = 0; + + HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferVS); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + mDeviceContext->VSSetConstantBuffers(1, 1, &mDriverConstantBufferVS); + } + + if (!mDriverConstantBufferPS) + { + D3D11_BUFFER_DESC constantBufferDescription = {0}; + constantBufferDescription.ByteWidth = sizeof(dx_PixelConstants); + constantBufferDescription.Usage = D3D11_USAGE_DEFAULT; + constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constantBufferDescription.CPUAccessFlags = 0; + constantBufferDescription.MiscFlags = 0; + constantBufferDescription.StructureByteStride = 0; + + HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferPS); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + mDeviceContext->PSSetConstantBuffers(1, 1, &mDriverConstantBufferPS); + } + + if (memcmp(&mVertexConstants, &mAppliedVertexConstants, sizeof(dx_VertexConstants)) != 0) + { + mDeviceContext->UpdateSubresource(mDriverConstantBufferVS, 0, NULL, &mVertexConstants, 16, 0); + memcpy(&mAppliedVertexConstants, &mVertexConstants, sizeof(dx_VertexConstants)); + } + + if (memcmp(&mPixelConstants, &mAppliedPixelConstants, sizeof(dx_PixelConstants)) != 0) + { + mDeviceContext->UpdateSubresource(mDriverConstantBufferPS, 0, NULL, &mPixelConstants, 16, 0); + memcpy(&mAppliedPixelConstants, &mPixelConstants, sizeof(dx_PixelConstants)); + } + + // needed for the point sprite geometry shader + if (mFeatureLevel >= D3D_FEATURE_LEVEL_10_0 && mCurrentGeometryConstantBuffer != mDriverConstantBufferPS) + { + mDeviceContext->GSSetConstantBuffers(0, 1, &mDriverConstantBufferPS); + mCurrentGeometryConstantBuffer = mDriverConstantBufferPS; + } +} + +void Renderer11::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) +{ + mClear->clearFramebuffer(clearParams, frameBuffer); + invalidateFramebufferSwizzles(frameBuffer); +} + +void Renderer11::markAllStateDirty() +{ + for (unsigned int rtIndex = 0; rtIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; rtIndex++) + { + mAppliedRenderTargetSerials[rtIndex] = 0; + } + mAppliedDepthbufferSerial = 0; + mAppliedStencilbufferSerial = 0; + mDepthStencilInitialized = false; + mRenderTargetDescInitialized = false; + + for (int i = 0; i < gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; i++) + { + mForceSetVertexSamplerStates[i] = true; + mCurVertexSRVs[i] = NULL; + } + for (int i = 0; i < gl::MAX_TEXTURE_IMAGE_UNITS; i++) + { + mForceSetPixelSamplerStates[i] = true; + mCurPixelSRVs[i] = NULL; + } + + mForceSetBlendState = true; + mForceSetRasterState = true; + mForceSetDepthStencilState = true; + mForceSetScissor = true; + mForceSetViewport = true; + + mAppliedIB = NULL; + mAppliedIBFormat = DXGI_FORMAT_UNKNOWN; + mAppliedIBOffset = 0; + + mAppliedVertexShader = NULL; + mAppliedGeometryShader = NULL; + mCurPointGeometryShader = NULL; + mAppliedPixelShader = NULL; + + for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + { + mAppliedTFBuffers[i] = NULL; + mAppliedTFOffsets[i] = 0; + } + + memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants)); + memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants)); + + mInputLayoutCache.markDirty(); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; i++) + { + mCurrentConstantBufferVS[i] = -1; + mCurrentConstantBufferPS[i] = -1; + } + + mCurrentVertexConstantBuffer = NULL; + mCurrentPixelConstantBuffer = NULL; + mCurrentGeometryConstantBuffer = NULL; + + mCurrentPrimitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; +} + +void Renderer11::releaseDeviceResources() +{ + mStateCache.clear(); + mInputLayoutCache.clear(); + + SafeDelete(mVertexDataManager); + SafeDelete(mIndexDataManager); + SafeDelete(mLineLoopIB); + SafeDelete(mTriangleFanIB); + SafeDelete(mBlit); + SafeDelete(mClear); + SafeDelete(mPixelTransfer); + + SafeRelease(mDriverConstantBufferVS); + SafeRelease(mDriverConstantBufferPS); + SafeRelease(mSyncQuery); +} + +void Renderer11::notifyDeviceLost() +{ + mDeviceLost = true; + mDisplay->notifyDeviceLost(); +} + +bool Renderer11::isDeviceLost() +{ + return mDeviceLost; +} + +// set notify to true to broadcast a message to all contexts of the device loss +bool Renderer11::testDeviceLost(bool notify) +{ + bool isLost = false; + + // GetRemovedReason is used to test if the device is removed + HRESULT result = mDevice->GetDeviceRemovedReason(); + isLost = d3d11::isDeviceLostError(result); + + if (isLost) + { + // Log error if this is a new device lost event + if (mDeviceLost == false) + { + ERR("The D3D11 device was removed: 0x%08X", result); + } + + // ensure we note the device loss -- + // we'll probably get this done again by notifyDeviceLost + // but best to remember it! + // Note that we don't want to clear the device loss status here + // -- this needs to be done by resetDevice + mDeviceLost = true; + if (notify) + { + notifyDeviceLost(); + } + } + + return isLost; +} + +bool Renderer11::testDeviceResettable() +{ + // determine if the device is resettable by creating a dummy device + PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); + + if (D3D11CreateDevice == NULL) + { + return false; + } + + D3D_FEATURE_LEVEL featureLevels[] = + { + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, +#if !defined(ANGLE_ENABLE_D3D9) + D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1, +#endif + }; + + ID3D11Device* dummyDevice; + D3D_FEATURE_LEVEL dummyFeatureLevel; + ID3D11DeviceContext* dummyContext; + + HRESULT result = D3D11CreateDevice(NULL, + D3D_DRIVER_TYPE_HARDWARE, + NULL, + #if defined(_DEBUG) + D3D11_CREATE_DEVICE_DEBUG, + #else + 0, + #endif + featureLevels, + ArraySize(featureLevels), + D3D11_SDK_VERSION, + &dummyDevice, + &dummyFeatureLevel, + &dummyContext); + + if (!mDevice || FAILED(result)) + { + return false; + } + + SafeRelease(dummyContext); + SafeRelease(dummyDevice); + + return true; +} + +void Renderer11::release() +{ + releaseDeviceResources(); + + SafeRelease(mDxgiFactory); + SafeRelease(mDxgiAdapter); + + if (mDeviceContext) + { + mDeviceContext->ClearState(); + mDeviceContext->Flush(); + SafeRelease(mDeviceContext); + } + + SafeRelease(mDevice); + + if (mD3d11Module) + { + FreeLibrary(mD3d11Module); + mD3d11Module = NULL; + } + + if (mDxgiModule) + { + FreeLibrary(mDxgiModule); + mDxgiModule = NULL; + } + + mCompiler.release(); +} + +bool Renderer11::resetDevice() +{ + // recreate everything + release(); + EGLint result = initialize(); + + if (result != EGL_SUCCESS) + { + ERR("Could not reinitialize D3D11 device: %08X", result); + return false; + } + + mDeviceLost = false; + + return true; +} + +DWORD Renderer11::getAdapterVendor() const +{ + return mAdapterDescription.VendorId; +} + +std::string Renderer11::getRendererDescription() const +{ + std::ostringstream rendererString; + + rendererString << mDescription; + rendererString << " Direct3D11"; + + rendererString << " vs_" << getMajorShaderModel() << "_" << getMinorShaderModel(); + rendererString << " ps_" << getMajorShaderModel() << "_" << getMinorShaderModel(); + + return rendererString.str(); +} + +GUID Renderer11::getAdapterIdentifier() const +{ + // Use the adapter LUID as our adapter ID + // This number is local to a machine is only guaranteed to be unique between restarts + META_ASSERT(sizeof(LUID) <= sizeof(GUID)); + GUID adapterId = {0}; + memcpy(&adapterId, &mAdapterDescription.AdapterLuid, sizeof(LUID)); + return adapterId; +} + +unsigned int Renderer11::getMaxVertexTextureImageUnits() const +{ + META_ASSERT(MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 <= gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS); + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return MAX_TEXTURE_IMAGE_UNITS_VTF_SM4; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; + default: UNREACHABLE(); + return 0; + } +} + +unsigned int Renderer11::getMaxCombinedTextureImageUnits() const +{ + return gl::MAX_TEXTURE_IMAGE_UNITS + getMaxVertexTextureImageUnits(); +} + +unsigned int Renderer11::getReservedVertexUniformVectors() const +{ + return 0; // Driver uniforms are stored in a separate constant buffer +} + +unsigned int Renderer11::getReservedFragmentUniformVectors() const +{ + return 0; // Driver uniforms are stored in a separate constant buffer +} + +unsigned int Renderer11::getMaxVertexUniformVectors() const +{ + META_ASSERT(MAX_VERTEX_UNIFORM_VECTORS_D3D11 <= D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT); + ASSERT(mFeatureLevel >= D3D_FEATURE_LEVEL_9_1); + return MAX_VERTEX_UNIFORM_VECTORS_D3D11; +} + +unsigned int Renderer11::getMaxFragmentUniformVectors() const +{ + META_ASSERT(MAX_FRAGMENT_UNIFORM_VECTORS_D3D11 <= D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT); + ASSERT(mFeatureLevel >= D3D_FEATURE_LEVEL_9_1); + return MAX_FRAGMENT_UNIFORM_VECTORS_D3D11; +} + +unsigned int Renderer11::getMaxVaryingVectors() const +{ + META_ASSERT(gl::IMPLEMENTATION_MAX_VARYING_VECTORS == D3D11_VS_OUTPUT_REGISTER_COUNT); + META_ASSERT(D3D11_VS_OUTPUT_REGISTER_COUNT <= D3D11_PS_INPUT_REGISTER_COUNT); + META_ASSERT(D3D10_VS_OUTPUT_REGISTER_COUNT <= D3D10_PS_INPUT_REGISTER_COUNT); + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: + return D3D11_VS_OUTPUT_REGISTER_COUNT - getReservedVaryings(); + case D3D_FEATURE_LEVEL_10_1: + return D3D10_1_VS_OUTPUT_REGISTER_COUNT - getReservedVaryings(); + case D3D_FEATURE_LEVEL_10_0: + return D3D10_VS_OUTPUT_REGISTER_COUNT - getReservedVaryings(); + case D3D_FEATURE_LEVEL_9_3: + return 10 - getReservedVaryings(); + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 8 - getReservedVaryings(); + default: UNREACHABLE(); + return 0; + } +} + +unsigned int Renderer11::getMaxVertexShaderUniformBuffers() const +{ + META_ASSERT(gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS >= D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT && + gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS >= D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT); + + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: + return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - getReservedVertexUniformBuffers(); + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - getReservedVertexUniformBuffers(); + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; + default: UNREACHABLE(); + return 0; + } +} + +unsigned int Renderer11::getMaxFragmentShaderUniformBuffers() const +{ + META_ASSERT(gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS >= D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT && + gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS >= D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT); + + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: + return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - getReservedFragmentUniformBuffers(); + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - getReservedFragmentUniformBuffers(); + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; + default: UNREACHABLE(); + return 0; + } +} + +unsigned int Renderer11::getReservedVertexUniformBuffers() const +{ + // we reserve one buffer for the application uniforms, and one for driver uniforms + return 2; +} + +unsigned int Renderer11::getReservedFragmentUniformBuffers() const +{ + // we reserve one buffer for the application uniforms, and one for driver uniforms + return 2; +} + +unsigned int Renderer11::getReservedVaryings() const +{ + // We potentially reserve varyings for gl_Position, dx_Position, gl_FragCoord and gl_PointSize + return 4; +} + + +unsigned int Renderer11::getMaxTransformFeedbackBuffers() const +{ + META_ASSERT(gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS >= D3D11_SO_BUFFER_SLOT_COUNT && + gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS >= D3D10_SO_BUFFER_SLOT_COUNT); + + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: + return D3D11_SO_BUFFER_SLOT_COUNT; + case D3D_FEATURE_LEVEL_10_1: + return D3D10_1_SO_BUFFER_SLOT_COUNT; + case D3D_FEATURE_LEVEL_10_0: + return D3D10_SO_BUFFER_SLOT_COUNT; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; + default: UNREACHABLE(); + return 0; + } +} + +unsigned int Renderer11::getMaxTransformFeedbackSeparateComponents() const +{ + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: + return getMaxTransformFeedbackInterleavedComponents() / getMaxTransformFeedbackBuffers(); + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + // D3D 10 and 10.1 only allow one output per output slot if an output slot other than zero + // is used. + return 4; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; + default: UNREACHABLE(); + return 0; + } +} + +unsigned int Renderer11::getMaxTransformFeedbackInterleavedComponents() const +{ + return (getMaxVaryingVectors() * 4); +} + +unsigned int Renderer11::getMaxUniformBufferSize() const +{ + // Each component is a 4-element vector of 4-byte units (floats) + const unsigned int bytesPerComponent = 4 * sizeof(float); + + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; + default: UNREACHABLE(); + return 0; + } +} + +bool Renderer11::getShareHandleSupport() const +{ + // We only currently support share handles with BGRA surfaces, because + // chrome needs BGRA. Once chrome fixes this, we should always support them. + // PIX doesn't seem to support using share handles, so disable them. + return getRendererExtensions().textureFormatBGRA8888 && !gl::perfActive(); +} + +bool Renderer11::getPostSubBufferSupport() const +{ + // D3D11 does not support present with dirty rectangles until D3D11.1 and DXGI 1.2. + return false; +} + +int Renderer11::getMaxRecommendedElementsIndices() const +{ + META_ASSERT(D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP == 32); + META_ASSERT(D3D10_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP == 32); + + // D3D11 allows up to 2^32 elements, but we report max signed int for convenience. + return std::numeric_limits<GLint>::max(); +} + +int Renderer11::getMaxRecommendedElementsVertices() const +{ + META_ASSERT(D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP == 32); + META_ASSERT(D3D10_REQ_DRAW_VERTEX_COUNT_2_TO_EXP == 32); + + // D3D11 allows up to 2^32 elements, but we report max signed int for convenience. + return std::numeric_limits<GLint>::max(); +} + +bool Renderer11::getSRGBTextureSupport() const +{ + return true; +} + +int Renderer11::getMajorShaderModel() const +{ + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MAJOR_VERSION; // 5 + case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MAJOR_VERSION; // 4 + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return D3D10_SHADER_MAJOR_VERSION; // 4 + default: UNREACHABLE(); return 0; + } +} + +int Renderer11::getMinorShaderModel() const +{ + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MINOR_VERSION; // 0 + case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MINOR_VERSION; // 1 + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D10_SHADER_MINOR_VERSION; // 0 + default: UNREACHABLE(); return 0; + } +} + +int Renderer11::getMinSwapInterval() const +{ + return 0; +} + +int Renderer11::getMaxSwapInterval() const +{ + return 4; +} + +int Renderer11::getMaxSupportedSamples() const +{ + return mMaxSupportedSamples; +} + +GLsizei Renderer11::getMaxSupportedFormatSamples(GLenum internalFormat) const +{ + DXGI_FORMAT format = gl_d3d11::GetRenderableFormat(internalFormat); + MultisampleSupportMap::const_iterator iter = mMultisampleSupportMap.find(format); + return (iter != mMultisampleSupportMap.end()) ? iter->second.maxSupportedSamples : 0; +} + +GLsizei Renderer11::getNumSampleCounts(GLenum internalFormat) const +{ + unsigned int numCounts = 0; + + // D3D11 supports multisampling for signed and unsigned format, but ES 3.0 does not + GLenum componentType = gl::GetComponentType(internalFormat); + if (componentType != GL_INT && componentType != GL_UNSIGNED_INT) + { + DXGI_FORMAT format = gl_d3d11::GetRenderableFormat(internalFormat); + MultisampleSupportMap::const_iterator iter = mMultisampleSupportMap.find(format); + + if (iter != mMultisampleSupportMap.end()) + { + const MultisampleSupportInfo& info = iter->second; + for (int i = 0; i < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; i++) + { + if (info.qualityLevels[i] > 0) + { + numCounts++; + } + } + } + } + + return numCounts; +} + +void Renderer11::getSampleCounts(GLenum internalFormat, GLsizei bufSize, GLint *params) const +{ + // D3D11 supports multisampling for signed and unsigned format, but ES 3.0 does not + GLenum componentType = gl::GetComponentType(internalFormat); + if (componentType == GL_INT || componentType == GL_UNSIGNED_INT) + { + return; + } + + DXGI_FORMAT format = gl_d3d11::GetRenderableFormat(internalFormat); + MultisampleSupportMap::const_iterator iter = mMultisampleSupportMap.find(format); + + if (iter != mMultisampleSupportMap.end()) + { + const MultisampleSupportInfo& info = iter->second; + int bufPos = 0; + for (int i = D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT - 1; i >= 0 && bufPos < bufSize; i--) + { + if (info.qualityLevels[i] > 0) + { + params[bufPos++] = i + 1; + } + } + } +} + +int Renderer11::getNearestSupportedSamples(DXGI_FORMAT format, unsigned int requested) const +{ + if (requested == 0) + { + return 0; + } + + MultisampleSupportMap::const_iterator iter = mMultisampleSupportMap.find(format); + if (iter != mMultisampleSupportMap.end()) + { + const MultisampleSupportInfo& info = iter->second; + for (unsigned int i = requested - 1; i < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; i++) + { + if (info.qualityLevels[i] > 0) + { + return i + 1; + } + } + } + + return -1; +} + +bool Renderer11::copyToRenderTarget(TextureStorageInterface2D *dest, TextureStorageInterface2D *source) +{ + if (source && dest) + { + TextureStorage11_2D *source11 = TextureStorage11_2D::makeTextureStorage11_2D(source->getStorageInstance()); + TextureStorage11_2D *dest11 = TextureStorage11_2D::makeTextureStorage11_2D(dest->getStorageInstance()); + + mDeviceContext->CopyResource(dest11->getResource(), source11->getResource()); + + dest11->invalidateSwizzleCache(); + + return true; + } + + return false; +} + +bool Renderer11::copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureStorageInterfaceCube *source) +{ + if (source && dest) + { + TextureStorage11_Cube *source11 = TextureStorage11_Cube::makeTextureStorage11_Cube(source->getStorageInstance()); + TextureStorage11_Cube *dest11 = TextureStorage11_Cube::makeTextureStorage11_Cube(dest->getStorageInstance()); + + mDeviceContext->CopyResource(dest11->getResource(), source11->getResource()); + + dest11->invalidateSwizzleCache(); + + return true; + } + + return false; +} + +bool Renderer11::copyToRenderTarget(TextureStorageInterface3D *dest, TextureStorageInterface3D *source) +{ + if (source && dest) + { + TextureStorage11_3D *source11 = TextureStorage11_3D::makeTextureStorage11_3D(source->getStorageInstance()); + TextureStorage11_3D *dest11 = TextureStorage11_3D::makeTextureStorage11_3D(dest->getStorageInstance()); + + mDeviceContext->CopyResource(dest11->getResource(), source11->getResource()); + + dest11->invalidateSwizzleCache(); + + return true; + } + + return false; +} + +bool Renderer11::copyToRenderTarget(TextureStorageInterface2DArray *dest, TextureStorageInterface2DArray *source) +{ + if (source && dest) + { + TextureStorage11_2DArray *source11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(source->getStorageInstance()); + TextureStorage11_2DArray *dest11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(dest->getStorageInstance()); + + mDeviceContext->CopyResource(dest11->getResource(), source11->getResource()); + + dest11->invalidateSwizzleCache(); + + return true; + } + + return false; +} + +bool Renderer11::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level) +{ + gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + if (!colorbuffer) + { + ERR("Failed to retrieve the color buffer from the frame buffer."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(colorbuffer->getRenderTarget()); + if (!sourceRenderTarget) + { + ERR("Failed to retrieve the render target from the frame buffer."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); + if (!source) + { + ERR("Failed to retrieve the render target view from the render target."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance()); + if (!storage11) + { + ERR("Failed to retrieve the texture storage from the destination."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + RenderTarget11 *destRenderTarget = RenderTarget11::makeRenderTarget11(storage11->getRenderTarget(level)); + if (!destRenderTarget) + { + ERR("Failed to retrieve the render target from the destination storage."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + ID3D11RenderTargetView *dest = destRenderTarget->getRenderTargetView(); + if (!dest) + { + ERR("Failed to retrieve the render target view from the destination render target."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + + gl::Box destArea(xoffset, yoffset, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); + + // Use nearest filtering because source and destination are the same size for the direct + // copy + bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, + destFormat, GL_NEAREST); + + storage11->invalidateSwizzleCacheLevel(level); + + return ret; +} + +bool Renderer11::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level) +{ + gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + if (!colorbuffer) + { + ERR("Failed to retrieve the color buffer from the frame buffer."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(colorbuffer->getRenderTarget()); + if (!sourceRenderTarget) + { + ERR("Failed to retrieve the render target from the frame buffer."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); + if (!source) + { + ERR("Failed to retrieve the render target view from the render target."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance()); + if (!storage11) + { + ERR("Failed to retrieve the texture storage from the destination."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + RenderTarget11 *destRenderTarget = RenderTarget11::makeRenderTarget11(storage11->getRenderTargetFace(target, level)); + if (!destRenderTarget) + { + ERR("Failed to retrieve the render target from the destination storage."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + ID3D11RenderTargetView *dest = destRenderTarget->getRenderTargetView(); + if (!dest) + { + ERR("Failed to retrieve the render target view from the destination render target."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + + gl::Box destArea(xoffset, yoffset, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); + + // Use nearest filtering because source and destination are the same size for the direct + // copy + bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, + destFormat, GL_NEAREST); + + storage11->invalidateSwizzleCacheLevel(level); + + return ret; +} + +bool Renderer11::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface3D *storage, GLint level) +{ + gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + if (!colorbuffer) + { + ERR("Failed to retrieve the color buffer from the frame buffer."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(colorbuffer->getRenderTarget()); + if (!sourceRenderTarget) + { + ERR("Failed to retrieve the render target from the frame buffer."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); + if (!source) + { + ERR("Failed to retrieve the render target view from the render target."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage->getStorageInstance()); + if (!storage11) + { + ERR("Failed to retrieve the texture storage from the destination."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + RenderTarget11 *destRenderTarget = RenderTarget11::makeRenderTarget11(storage11->getRenderTargetLayer(level, zOffset)); + if (!destRenderTarget) + { + ERR("Failed to retrieve the render target from the destination storage."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + ID3D11RenderTargetView *dest = destRenderTarget->getRenderTargetView(); + if (!dest) + { + ERR("Failed to retrieve the render target view from the destination render target."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + + gl::Box destArea(xoffset, yoffset, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); + + // Use nearest filtering because source and destination are the same size for the direct + // copy + bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, + destFormat, GL_NEAREST); + + storage11->invalidateSwizzleCacheLevel(level); + + return ret; +} + +bool Renderer11::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface2DArray *storage, GLint level) +{ + gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + if (!colorbuffer) + { + ERR("Failed to retrieve the color buffer from the frame buffer."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(colorbuffer->getRenderTarget()); + if (!sourceRenderTarget) + { + ERR("Failed to retrieve the render target from the frame buffer."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); + if (!source) + { + ERR("Failed to retrieve the render target view from the render target."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage->getStorageInstance()); + if (!storage11) + { + SafeRelease(source); + ERR("Failed to retrieve the texture storage from the destination."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + RenderTarget11 *destRenderTarget = RenderTarget11::makeRenderTarget11(storage11->getRenderTargetLayer(level, zOffset)); + if (!destRenderTarget) + { + SafeRelease(source); + ERR("Failed to retrieve the render target from the destination storage."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + ID3D11RenderTargetView *dest = destRenderTarget->getRenderTargetView(); + if (!dest) + { + ERR("Failed to retrieve the render target view from the destination render target."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + + gl::Box destArea(xoffset, yoffset, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); + + // Use nearest filtering because source and destination are the same size for the direct + // copy + bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, + destFormat, GL_NEAREST); + + storage11->invalidateSwizzleCacheLevel(level); + + return ret; +} + +void Renderer11::unapplyRenderTargets() +{ + setOneTimeRenderTarget(NULL); +} + +void Renderer11::setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView) +{ + ID3D11RenderTargetView *rtvArray[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {NULL}; + + rtvArray[0] = renderTargetView; + + mDeviceContext->OMSetRenderTargets(getRendererCaps().maxDrawBuffers, rtvArray, NULL); + + // Do not preserve the serial for this one-time-use render target + for (unsigned int rtIndex = 0; rtIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; rtIndex++) + { + mAppliedRenderTargetSerials[rtIndex] = 0; + } +} + +RenderTarget *Renderer11::createRenderTarget(SwapChain *swapChain, bool depth) +{ + SwapChain11 *swapChain11 = SwapChain11::makeSwapChain11(swapChain); + RenderTarget11 *renderTarget = NULL; + + if (depth) + { + // Note: depth stencil may be NULL for 0 sized surfaces + renderTarget = new RenderTarget11(this, swapChain11->getDepthStencil(), + swapChain11->getDepthStencilTexture(), + swapChain11->getDepthStencilShaderResource(), + swapChain11->getWidth(), swapChain11->getHeight(), 1); + } + else + { + // Note: render target may be NULL for 0 sized surfaces + renderTarget = new RenderTarget11(this, swapChain11->getRenderTarget(), + swapChain11->getOffscreenTexture(), + swapChain11->getRenderTargetShaderResource(), + swapChain11->getWidth(), swapChain11->getHeight(), 1); + } + return renderTarget; +} + +RenderTarget *Renderer11::createRenderTarget(int width, int height, GLenum format, GLsizei samples) +{ + RenderTarget11 *renderTarget = new RenderTarget11(this, width, height, format, samples); + return renderTarget; +} + +ShaderExecutable *Renderer11::loadExecutable(const void *function, size_t length, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers) +{ + ShaderExecutable11 *executable = NULL; + HRESULT result; + + switch (type) + { + case rx::SHADER_VERTEX: + { + ID3D11VertexShader *vertexShader = NULL; + ID3D11GeometryShader *streamOutShader = NULL; + + result = mDevice->CreateVertexShader(function, length, NULL, &vertexShader); + ASSERT(SUCCEEDED(result)); + + if (transformFeedbackVaryings.size() > 0) + { + std::vector<D3D11_SO_DECLARATION_ENTRY> soDeclaration; + for (size_t i = 0; i < transformFeedbackVaryings.size(); i++) + { + const gl::LinkedVarying &varying = transformFeedbackVaryings[i]; + GLenum transposedType = gl::TransposeMatrixType(varying.type); + + for (size_t j = 0; j < varying.semanticIndexCount; j++) + { + D3D11_SO_DECLARATION_ENTRY entry = { 0 }; + entry.Stream = 0; + entry.SemanticName = varying.semanticName.c_str(); + entry.SemanticIndex = varying.semanticIndex + j; + entry.StartComponent = 0; + entry.ComponentCount = gl::VariableColumnCount(transposedType); + entry.OutputSlot = (separatedOutputBuffers ? i : 0); + soDeclaration.push_back(entry); + } + } + + result = mDevice->CreateGeometryShaderWithStreamOutput(function, length, soDeclaration.data(), soDeclaration.size(), + NULL, 0, 0, NULL, &streamOutShader); + ASSERT(SUCCEEDED(result)); + } + + if (vertexShader) + { + executable = new ShaderExecutable11(function, length, vertexShader, streamOutShader); + } + } + break; + case rx::SHADER_PIXEL: + { + ID3D11PixelShader *pixelShader = NULL; + + result = mDevice->CreatePixelShader(function, length, NULL, &pixelShader); + ASSERT(SUCCEEDED(result)); + + if (pixelShader) + { + executable = new ShaderExecutable11(function, length, pixelShader); + } + } + break; + case rx::SHADER_GEOMETRY: + { + ID3D11GeometryShader *geometryShader = NULL; + + result = mDevice->CreateGeometryShader(function, length, NULL, &geometryShader); + ASSERT(SUCCEEDED(result)); + + if (geometryShader) + { + executable = new ShaderExecutable11(function, length, geometryShader); + } + } + break; + default: + UNREACHABLE(); + break; + } + + return executable; +} + +ShaderExecutable *Renderer11::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround) +{ + const char *profileType = NULL; + switch (type) + { + case rx::SHADER_VERTEX: + profileType = "vs"; + break; + case rx::SHADER_PIXEL: + profileType = "ps"; + break; + case rx::SHADER_GEOMETRY: + profileType = "gs"; + break; + default: + UNREACHABLE(); + return NULL; + } + + const char *profileVersion = NULL; + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: + profileVersion = "5_0"; + break; + case D3D_FEATURE_LEVEL_10_1: + profileVersion = "4_1"; + break; + case D3D_FEATURE_LEVEL_10_0: + profileVersion = "4_0"; + break; + case D3D_FEATURE_LEVEL_9_3: + profileVersion = "4_0_level_9_3"; + break; + case D3D_FEATURE_LEVEL_9_2: + profileVersion = "4_0_level_9_2"; + break; + case D3D_FEATURE_LEVEL_9_1: + profileVersion = "4_0_level_9_1"; + break; + default: + UNREACHABLE(); + return NULL; + } + + char profile[32]; + snprintf(profile, ArraySize(profile), "%s_%s", profileType, profileVersion); + + UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL0; + + if (gl::perfActive()) + { +#ifndef NDEBUG + flags = D3DCOMPILE_SKIP_OPTIMIZATION; +#endif + + flags |= D3DCOMPILE_DEBUG; + + std::string sourcePath = getTempPath(); + std::string sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(shaderHLSL); + writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size()); + } + + // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options. + // Try the default flags first and if compilation fails, try some alternatives. + const UINT extraFlags[] = + { + flags, + flags | D3DCOMPILE_SKIP_VALIDATION, + flags | D3DCOMPILE_SKIP_OPTIMIZATION + }; + + const static char *extraFlagNames[] = + { + "default", + "skip validation", + "skip optimization" + }; + + int attempts = ArraySize(extraFlags); + + ID3DBlob *binary = (ID3DBlob*)mCompiler.compileToBinary(infoLog, shaderHLSL, profile, extraFlags, extraFlagNames, attempts); + if (!binary) + { + return NULL; + } + + ShaderExecutable *executable = loadExecutable((DWORD *)binary->GetBufferPointer(), binary->GetBufferSize(), type, + transformFeedbackVaryings, separatedOutputBuffers); + SafeRelease(binary); + + return executable; +} + +rx::UniformStorage *Renderer11::createUniformStorage(size_t storageSize) +{ + return new UniformStorage11(this, storageSize); +} + +VertexBuffer *Renderer11::createVertexBuffer() +{ + return new VertexBuffer11(this); +} + +IndexBuffer *Renderer11::createIndexBuffer() +{ + return new IndexBuffer11(this); +} + +BufferImpl *Renderer11::createBuffer() +{ + return new Buffer11(this); +} + +VertexArrayImpl *Renderer11::createVertexArray() +{ + return new VertexArray11(this); +} + +QueryImpl *Renderer11::createQuery(GLenum type) +{ + return new Query11(this, type); +} + +FenceImpl *Renderer11::createFence() +{ + return new Fence11(this); +} + +bool Renderer11::supportsFastCopyBufferToTexture(GLenum internalFormat) const +{ + ASSERT(getRendererExtensions().pixelBufferObject); + + // sRGB formats do not work with D3D11 buffer SRVs + if (gl::GetColorEncoding(internalFormat) == GL_SRGB) + { + return false; + } + + // We cannot support direct copies to non-color-renderable formats + if (gl_d3d11::GetRTVFormat(internalFormat) != DXGI_FORMAT_UNKNOWN) + { + return false; + } + + // We skip all 3-channel formats since sometimes format support is missing + if (gl::GetComponentCount(internalFormat) == 3) + { + return false; + } + + // We don't support formats which we can't represent without conversion + if (getNativeTextureFormat(internalFormat) != internalFormat) + { + return false; + } + + return true; +} + +bool Renderer11::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +{ + ASSERT(supportsFastCopyBufferToTexture(destinationFormat)); + return mPixelTransfer->copyBufferToTexture(unpack, offset, destRenderTarget, destinationFormat, sourcePixelsType, destArea); +} + +bool Renderer11::getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndex, ID3D11Texture2D **resource) +{ + ASSERT(colorbuffer != NULL); + + RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(colorbuffer->getRenderTarget()); + if (renderTarget) + { + *subresourceIndex = renderTarget->getSubresourceIndex(); + + ID3D11RenderTargetView *colorBufferRTV = renderTarget->getRenderTargetView(); + if (colorBufferRTV) + { + ID3D11Resource *textureResource = NULL; + colorBufferRTV->GetResource(&textureResource); + + if (textureResource) + { + HRESULT result = textureResource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)resource); + SafeRelease(textureResource); + + if (SUCCEEDED(result)) + { + return true; + } + else + { + ERR("Failed to extract the ID3D11Texture2D from the render target resource, " + "HRESULT: 0x%X.", result); + } + } + } + } + + return false; +} + +bool Renderer11::blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, + const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter) +{ + if (blitRenderTarget) + { + gl::FramebufferAttachment *readBuffer = readTarget->getReadColorbuffer(); + + if (!readBuffer) + { + ERR("Failed to retrieve the read buffer from the read framebuffer."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + RenderTarget *readRenderTarget = readBuffer->getRenderTarget(); + + for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) + { + if (drawTarget->isEnabledColorAttachment(colorAttachment)) + { + gl::FramebufferAttachment *drawBuffer = drawTarget->getColorbuffer(colorAttachment); + + if (!drawBuffer) + { + ERR("Failed to retrieve the draw buffer from the draw framebuffer."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + RenderTarget *drawRenderTarget = drawBuffer->getRenderTarget(); + + if (!blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, filter, scissor, + blitRenderTarget, false, false)) + { + return false; + } + } + } + } + + if (blitDepth || blitStencil) + { + gl::FramebufferAttachment *readBuffer = readTarget->getDepthOrStencilbuffer(); + gl::FramebufferAttachment *drawBuffer = drawTarget->getDepthOrStencilbuffer(); + + if (!readBuffer) + { + ERR("Failed to retrieve the read depth-stencil buffer from the read framebuffer."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + if (!drawBuffer) + { + ERR("Failed to retrieve the draw depth-stencil buffer from the draw framebuffer."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + RenderTarget *readRenderTarget = readBuffer->getDepthStencil(); + RenderTarget *drawRenderTarget = drawBuffer->getDepthStencil(); + + if (!blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, filter, scissor, + false, blitDepth, blitStencil)) + { + return false; + } + } + + invalidateFramebufferSwizzles(drawTarget); + + return true; +} + +void Renderer11::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, void* pixels) +{ + ID3D11Texture2D *colorBufferTexture = NULL; + unsigned int subresourceIndex = 0; + + gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + + if (colorbuffer && getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture)) + { + gl::Rectangle area; + area.x = x; + area.y = y; + area.width = width; + area.height = height; + + if (pack.pixelBuffer.get() != NULL) + { + rx::Buffer11 *packBufferStorage = Buffer11::makeBuffer11(pack.pixelBuffer.get()->getImplementation()); + PackPixelsParams packParams(area, format, type, outputPitch, pack, reinterpret_cast<ptrdiff_t>(pixels)); + packBufferStorage->packPixels(colorBufferTexture, subresourceIndex, packParams); + } + else + { + readTextureData(colorBufferTexture, subresourceIndex, area, format, type, outputPitch, pack, pixels); + } + + SafeRelease(colorBufferTexture); + } +} + +Image *Renderer11::createImage() +{ + return new Image11(); +} + +void Renderer11::generateMipmap(Image *dest, Image *src) +{ + Image11 *dest11 = Image11::makeImage11(dest); + Image11 *src11 = Image11::makeImage11(src); + Image11::generateMipmap(dest11, src11); +} + +TextureStorage *Renderer11::createTextureStorage2D(SwapChain *swapChain) +{ + SwapChain11 *swapChain11 = SwapChain11::makeSwapChain11(swapChain); + return new TextureStorage11_2D(this, swapChain11); +} + +TextureStorage *Renderer11::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) +{ + return new TextureStorage11_2D(this, internalformat, renderTarget, width, height, levels); +} + +TextureStorage *Renderer11::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels) +{ + return new TextureStorage11_Cube(this, internalformat, renderTarget, size, levels); +} + +TextureStorage *Renderer11::createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +{ + return new TextureStorage11_3D(this, internalformat, renderTarget, width, height, depth, levels); +} + +TextureStorage *Renderer11::createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +{ + return new TextureStorage11_2DArray(this, internalformat, renderTarget, width, height, depth, levels); +} + +Texture2DImpl *Renderer11::createTexture2D() +{ + return new TextureD3D_2D(this); +} + +TextureCubeImpl *Renderer11::createTextureCube() +{ + return new TextureD3D_Cube(this); +} + +Texture3DImpl *Renderer11::createTexture3D() +{ + return new TextureD3D_3D(this); +} + +Texture2DArrayImpl *Renderer11::createTexture2DArray() +{ + return new TextureD3D_2DArray(this); +} + +void Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, void *pixels) +{ + ASSERT(area.width >= 0); + ASSERT(area.height >= 0); + + D3D11_TEXTURE2D_DESC textureDesc; + texture->GetDesc(&textureDesc); + + // Clamp read region to the defined texture boundaries, preventing out of bounds reads + // and reads of uninitialized data. + gl::Rectangle safeArea; + safeArea.x = gl::clamp(area.x, 0, static_cast<int>(textureDesc.Width)); + safeArea.y = gl::clamp(area.y, 0, static_cast<int>(textureDesc.Height)); + safeArea.width = gl::clamp(area.width + std::min(area.x, 0), 0, + static_cast<int>(textureDesc.Width) - safeArea.x); + safeArea.height = gl::clamp(area.height + std::min(area.y, 0), 0, + static_cast<int>(textureDesc.Height) - safeArea.y); + + ASSERT(safeArea.x >= 0 && safeArea.y >= 0); + ASSERT(safeArea.x + safeArea.width <= static_cast<int>(textureDesc.Width)); + ASSERT(safeArea.y + safeArea.height <= static_cast<int>(textureDesc.Height)); + + if (safeArea.width == 0 || safeArea.height == 0) + { + // no work to do + return; + } + + D3D11_TEXTURE2D_DESC stagingDesc; + stagingDesc.Width = safeArea.width; + stagingDesc.Height = safeArea.height; + stagingDesc.MipLevels = 1; + stagingDesc.ArraySize = 1; + stagingDesc.Format = textureDesc.Format; + stagingDesc.SampleDesc.Count = 1; + stagingDesc.SampleDesc.Quality = 0; + stagingDesc.Usage = D3D11_USAGE_STAGING; + stagingDesc.BindFlags = 0; + stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + stagingDesc.MiscFlags = 0; + + ID3D11Texture2D* stagingTex = NULL; + HRESULT result = mDevice->CreateTexture2D(&stagingDesc, NULL, &stagingTex); + if (FAILED(result)) + { + ERR("Failed to create staging texture for readPixels, HRESULT: 0x%X.", result); + return; + } + + ID3D11Texture2D* srcTex = NULL; + if (textureDesc.SampleDesc.Count > 1) + { + D3D11_TEXTURE2D_DESC resolveDesc; + resolveDesc.Width = textureDesc.Width; + resolveDesc.Height = textureDesc.Height; + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; + resolveDesc.Format = textureDesc.Format; + resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Quality = 0; + resolveDesc.Usage = D3D11_USAGE_DEFAULT; + resolveDesc.BindFlags = 0; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; + + result = mDevice->CreateTexture2D(&resolveDesc, NULL, &srcTex); + if (FAILED(result)) + { + ERR("Failed to create resolve texture for readPixels, HRESULT: 0x%X.", result); + SafeRelease(stagingTex); + return; + } + + mDeviceContext->ResolveSubresource(srcTex, 0, texture, subResource, textureDesc.Format); + subResource = 0; + } + else + { + srcTex = texture; + srcTex->AddRef(); + } + + D3D11_BOX srcBox; + srcBox.left = static_cast<UINT>(safeArea.x); + srcBox.right = static_cast<UINT>(safeArea.x + safeArea.width); + srcBox.top = static_cast<UINT>(safeArea.y); + srcBox.bottom = static_cast<UINT>(safeArea.y + safeArea.height); + srcBox.front = 0; + srcBox.back = 1; + + mDeviceContext->CopySubresourceRegion(stagingTex, 0, 0, 0, 0, srcTex, subResource, &srcBox); + + SafeRelease(srcTex); + + PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0); + packPixels(stagingTex, packParams, pixels); + + SafeRelease(stagingTex); +} + +void Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams ¶ms, void *pixelsOut) +{ + D3D11_TEXTURE2D_DESC textureDesc; + readTexture->GetDesc(&textureDesc); + + D3D11_MAPPED_SUBRESOURCE mapping; + HRESULT hr = mDeviceContext->Map(readTexture, 0, D3D11_MAP_READ, 0, &mapping); + UNUSED_ASSERTION_VARIABLE(hr); + ASSERT(SUCCEEDED(hr)); + + unsigned char *source; + int inputPitch; + if (params.pack.reverseRowOrder) + { + source = static_cast<unsigned char*>(mapping.pData) + mapping.RowPitch * (params.area.height - 1); + inputPitch = -static_cast<int>(mapping.RowPitch); + } + else + { + source = static_cast<unsigned char*>(mapping.pData); + inputPitch = static_cast<int>(mapping.RowPitch); + } + + GLenum sourceInternalFormat = d3d11_gl::GetInternalFormat(textureDesc.Format); + GLenum sourceFormat = gl::GetFormat(sourceInternalFormat); + GLenum sourceType = gl::GetType(sourceInternalFormat); + + GLuint sourcePixelSize = gl::GetPixelBytes(sourceInternalFormat); + + if (sourceFormat == params.format && sourceType == params.type) + { + unsigned char *dest = static_cast<unsigned char*>(pixelsOut) + params.offset; + for (int y = 0; y < params.area.height; y++) + { + memcpy(dest + y * params.outputPitch, source + y * inputPitch, params.area.width * sourcePixelSize); + } + } + else + { + GLenum destInternalFormat = gl::GetSizedInternalFormat(params.format, params.type); + GLuint destPixelSize = gl::GetPixelBytes(destInternalFormat); + + ColorCopyFunction fastCopyFunc = d3d11::GetFastCopyFunction(textureDesc.Format, params.format, params.type); + if (fastCopyFunc) + { + // Fast copy is possible through some special function + for (int y = 0; y < params.area.height; y++) + { + for (int x = 0; x < params.area.width; x++) + { + void *dest = static_cast<unsigned char*>(pixelsOut) + params.offset + y * params.outputPitch + x * destPixelSize; + void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourcePixelSize; + + fastCopyFunc(src, dest); + } + } + } + else + { + ColorReadFunction readFunc = d3d11::GetColorReadFunction(textureDesc.Format); + ColorWriteFunction writeFunc = gl::GetColorWriteFunction(params.format, params.type); + + unsigned char temp[16]; // Maximum size of any Color<T> type used. + META_ASSERT(sizeof(temp) >= sizeof(gl::ColorF) && + sizeof(temp) >= sizeof(gl::ColorUI) && + sizeof(temp) >= sizeof(gl::ColorI)); + + for (int y = 0; y < params.area.height; y++) + { + for (int x = 0; x < params.area.width; x++) + { + void *dest = static_cast<unsigned char*>(pixelsOut) + params.offset + y * params.outputPitch + x * destPixelSize; + void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourcePixelSize; + + // readFunc and writeFunc will be using the same type of color, CopyTexImage + // will not allow the copy otherwise. + readFunc(src, temp); + writeFunc(temp, dest); + } + } + } + } + + mDeviceContext->Unmap(readTexture, 0); +} + +bool Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget, + RenderTarget *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor, + bool colorBlit, bool depthBlit, bool stencilBlit) +{ + // Since blitRenderbufferRect is called for each render buffer that needs to be blitted, + // it should never be the case that both color and depth/stencil need to be blitted at + // at the same time. + ASSERT(colorBlit != (depthBlit || stencilBlit)); + + bool result = true; + + RenderTarget11 *drawRenderTarget11 = RenderTarget11::makeRenderTarget11(drawRenderTarget); + if (!drawRenderTarget) + { + ERR("Failed to retrieve the draw render target from the draw framebuffer."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + ID3D11Resource *drawTexture = drawRenderTarget11->getTexture(); + unsigned int drawSubresource = drawRenderTarget11->getSubresourceIndex(); + ID3D11RenderTargetView *drawRTV = drawRenderTarget11->getRenderTargetView(); + ID3D11DepthStencilView *drawDSV = drawRenderTarget11->getDepthStencilView(); + + RenderTarget11 *readRenderTarget11 = RenderTarget11::makeRenderTarget11(readRenderTarget); + if (!readRenderTarget) + { + ERR("Failed to retrieve the read render target from the read framebuffer."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + ID3D11Resource *readTexture = NULL; + ID3D11ShaderResourceView *readSRV = NULL; + unsigned int readSubresource = 0; + if (readRenderTarget->getSamples() > 0) + { + ID3D11Resource *unresolvedResource = readRenderTarget11->getTexture(); + ID3D11Texture2D *unresolvedTexture = d3d11::DynamicCastComObject<ID3D11Texture2D>(unresolvedResource); + + if (unresolvedTexture) + { + readTexture = resolveMultisampledTexture(unresolvedTexture, readRenderTarget11->getSubresourceIndex()); + readSubresource = 0; + + SafeRelease(unresolvedTexture); + + HRESULT hresult = mDevice->CreateShaderResourceView(readTexture, NULL, &readSRV); + if (FAILED(hresult)) + { + SafeRelease(readTexture); + return gl::error(GL_OUT_OF_MEMORY, false); + } + } + } + else + { + readTexture = readRenderTarget11->getTexture(); + readTexture->AddRef(); + readSubresource = readRenderTarget11->getSubresourceIndex(); + readSRV = readRenderTarget11->getShaderResourceView(); + readSRV->AddRef(); + } + + if (!readTexture || !readSRV) + { + SafeRelease(readTexture); + SafeRelease(readSRV); + ERR("Failed to retrieve the read render target view from the read render target."); + return gl::error(GL_OUT_OF_MEMORY, false); + } + + gl::Extents readSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); + gl::Extents drawSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); + + bool scissorNeeded = scissor && gl::ClipRectangle(drawRect, *scissor, NULL); + + bool wholeBufferCopy = !scissorNeeded && + readRect.x == 0 && readRect.width == readSize.width && + readRect.y == 0 && readRect.height == readSize.height && + drawRect.x == 0 && drawRect.width == drawSize.width && + drawRect.y == 0 && drawRect.height == drawSize.height; + + bool stretchRequired = readRect.width != drawRect.width || readRect.height != drawRect.height; + + bool flipRequired = readRect.width < 0 || readRect.height < 0 || drawRect.width < 0 || drawRect.height < 0; + + bool outOfBounds = readRect.x < 0 || readRect.x + readRect.width > readSize.width || + readRect.y < 0 || readRect.y + readRect.height > readSize.height || + drawRect.x < 0 || drawRect.x + drawRect.width > drawSize.width || + drawRect.y < 0 || drawRect.y + drawRect.height > drawSize.height; + + bool hasDepth = gl::GetDepthBits(drawRenderTarget11->getActualFormat()) > 0; + bool hasStencil = gl::GetStencilBits(drawRenderTarget11->getActualFormat()) > 0; + bool partialDSBlit = (hasDepth && depthBlit) != (hasStencil && stencilBlit); + + if (readRenderTarget11->getActualFormat() == drawRenderTarget->getActualFormat() && + !stretchRequired && !outOfBounds && !flipRequired && !partialDSBlit && + (!(depthBlit || stencilBlit) || wholeBufferCopy)) + { + UINT dstX = drawRect.x; + UINT dstY = drawRect.y; + + D3D11_BOX readBox; + readBox.left = readRect.x; + readBox.right = readRect.x + readRect.width; + readBox.top = readRect.y; + readBox.bottom = readRect.y + readRect.height; + readBox.front = 0; + readBox.back = 1; + + if (scissorNeeded) + { + // drawRect is guaranteed to have positive width and height because stretchRequired is false. + ASSERT(drawRect.width >= 0 || drawRect.height >= 0); + + if (drawRect.x < scissor->x) + { + dstX = scissor->x; + readBox.left += (scissor->x - drawRect.x); + } + if (drawRect.y < scissor->y) + { + dstY = scissor->y; + readBox.top += (scissor->y - drawRect.y); + } + if (drawRect.x + drawRect.width > scissor->x + scissor->width) + { + readBox.right -= ((drawRect.x + drawRect.width) - (scissor->x + scissor->width)); + } + if (drawRect.y + drawRect.height > scissor->y + scissor->height) + { + readBox.bottom -= ((drawRect.y + drawRect.height) - (scissor->y + scissor->height)); + } + } + + // D3D11 needs depth-stencil CopySubresourceRegions to have a NULL pSrcBox + // We also require complete framebuffer copies for depth-stencil blit. + D3D11_BOX *pSrcBox = wholeBufferCopy ? NULL : &readBox; + + mDeviceContext->CopySubresourceRegion(drawTexture, drawSubresource, dstX, dstY, 0, + readTexture, readSubresource, pSrcBox); + result = true; + } + else + { + gl::Box readArea(readRect.x, readRect.y, 0, readRect.width, readRect.height, 1); + gl::Box drawArea(drawRect.x, drawRect.y, 0, drawRect.width, drawRect.height, 1); + + if (depthBlit && stencilBlit) + { + result = mBlit->copyDepthStencil(readTexture, readSubresource, readArea, readSize, + drawTexture, drawSubresource, drawArea, drawSize, + scissor); + } + else if (depthBlit) + { + result = mBlit->copyDepth(readSRV, readArea, readSize, drawDSV, drawArea, drawSize, + scissor); + } + else if (stencilBlit) + { + result = mBlit->copyStencil(readTexture, readSubresource, readArea, readSize, + drawTexture, drawSubresource, drawArea, drawSize, + scissor); + } + else + { + GLenum format = gl::GetFormat(drawRenderTarget->getInternalFormat()); + result = mBlit->copyTexture(readSRV, readArea, readSize, drawRTV, drawArea, drawSize, + scissor, format, filter); + } + } + + SafeRelease(readTexture); + SafeRelease(readSRV); + + return result; +} + +ID3D11Texture2D *Renderer11::resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource) +{ + D3D11_TEXTURE2D_DESC textureDesc; + source->GetDesc(&textureDesc); + + if (textureDesc.SampleDesc.Count > 1) + { + D3D11_TEXTURE2D_DESC resolveDesc; + resolveDesc.Width = textureDesc.Width; + resolveDesc.Height = textureDesc.Height; + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; + resolveDesc.Format = textureDesc.Format; + resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Quality = 0; + resolveDesc.Usage = textureDesc.Usage; + resolveDesc.BindFlags = textureDesc.BindFlags; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; + + ID3D11Texture2D *resolveTexture = NULL; + HRESULT result = mDevice->CreateTexture2D(&resolveDesc, NULL, &resolveTexture); + if (FAILED(result)) + { + ERR("Failed to create a multisample resolve texture, HRESULT: 0x%X.", result); + return NULL; + } + + mDeviceContext->ResolveSubresource(resolveTexture, 0, source, subresource, textureDesc.Format); + return resolveTexture; + } + else + { + source->AddRef(); + return source; + } +} + +void Renderer11::invalidateFBOAttachmentSwizzles(gl::FramebufferAttachment *attachment, int mipLevel) +{ + ASSERT(attachment->isTexture()); + TextureStorage *texStorage = attachment->getTextureStorage(); + if (texStorage) + { + TextureStorage11 *texStorage11 = TextureStorage11::makeTextureStorage11(texStorage); + if (!texStorage11) + { + ERR("texture storage pointer unexpectedly null."); + return; + } + + texStorage11->invalidateSwizzleCacheLevel(mipLevel); + } +} + +void Renderer11::invalidateFramebufferSwizzles(gl::Framebuffer *framebuffer) +{ + for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) + { + gl::FramebufferAttachment *attachment = framebuffer->getColorbuffer(colorAttachment); + if (attachment && attachment->isTexture()) + { + invalidateFBOAttachmentSwizzles(attachment, attachment->mipLevel()); + } + } + + gl::FramebufferAttachment *depthAttachment = framebuffer->getDepthbuffer(); + if (depthAttachment && depthAttachment->isTexture()) + { + invalidateFBOAttachmentSwizzles(depthAttachment, depthAttachment->mipLevel()); + } + + gl::FramebufferAttachment *stencilAttachment = framebuffer->getStencilbuffer(); + if (stencilAttachment && stencilAttachment->isTexture()) + { + invalidateFBOAttachmentSwizzles(stencilAttachment, stencilAttachment->mipLevel()); + } +} + +bool Renderer11::getLUID(LUID *adapterLuid) const +{ + adapterLuid->HighPart = 0; + adapterLuid->LowPart = 0; + + if (!mDxgiAdapter) + { + return false; + } + + DXGI_ADAPTER_DESC adapterDesc; + if (FAILED(mDxgiAdapter->GetDesc(&adapterDesc))) + { + return false; + } + + *adapterLuid = adapterDesc.AdapterLuid; + return true; +} + +GLenum Renderer11::getNativeTextureFormat(GLenum internalFormat) const +{ + return d3d11_gl::GetInternalFormat(gl_d3d11::GetTexFormat(internalFormat)); +} + +rx::VertexConversionType Renderer11::getVertexConversionType(const gl::VertexFormat &vertexFormat) const +{ + return gl_d3d11::GetVertexConversionType(vertexFormat); +} + +GLenum Renderer11::getVertexComponentType(const gl::VertexFormat &vertexFormat) const +{ + return d3d11::GetComponentType(gl_d3d11::GetNativeVertexFormat(vertexFormat)); +} + +Renderer11::MultisampleSupportInfo Renderer11::getMultisampleSupportInfo(DXGI_FORMAT format) +{ + MultisampleSupportInfo supportInfo = { 0 }; + + UINT formatSupport; + HRESULT result; + + result = mDevice->CheckFormatSupport(format, &formatSupport); + if (SUCCEEDED(result) && (formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET)) + { + for (unsigned int i = 1; i <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; i++) + { + result = mDevice->CheckMultisampleQualityLevels(format, i, &supportInfo.qualityLevels[i - 1]); + if (SUCCEEDED(result) && supportInfo.qualityLevels[i - 1] > 0) + { + supportInfo.maxSupportedSamples = std::max(supportInfo.maxSupportedSamples, i); + } + else + { + supportInfo.qualityLevels[i - 1] = 0; + } + } + } + + return supportInfo; +} + +void Renderer11::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const +{ + d3d11_gl::GenerateCaps(mDevice, outCaps, outTextureCaps, outExtensions); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h new file mode 100644 index 0000000000..b54f75d859 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h @@ -0,0 +1,375 @@ +// +// 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. +// + +// Renderer11.h: Defines a back-end specific class for the D3D11 renderer. + +#ifndef LIBGLESV2_RENDERER_RENDERER11_H_ +#define LIBGLESV2_RENDERER_RENDERER11_H_ + +#include "common/angleutils.h" +#include "libGLESv2/angletypes.h" +#include "common/mathutil.h" + +#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/renderer/d3d/HLSLCompiler.h" +#include "libGLESv2/renderer/d3d/d3d11/RenderStateCache.h" +#include "libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h" +#include "libGLESv2/renderer/RenderTarget.h" + +namespace gl +{ +class FramebufferAttachment; +} + +namespace rx +{ + +class VertexDataManager; +class IndexDataManager; +class StreamingIndexBufferInterface; +class Blit11; +class Clear11; +class PixelTransfer11; +struct PackPixelsParams; + +enum +{ + MAX_VERTEX_UNIFORM_VECTORS_D3D11 = 1024, + MAX_FRAGMENT_UNIFORM_VECTORS_D3D11 = 1024 +}; + +class Renderer11 : public Renderer +{ + public: + Renderer11(egl::Display *display, EGLNativeDisplayType hDc, EGLint requestedDisplay); + virtual ~Renderer11(); + + static Renderer11 *makeRenderer11(Renderer *renderer); + + virtual EGLint initialize(); + virtual bool resetDevice(); + + virtual int generateConfigs(ConfigDesc **configDescList); + virtual void deleteConfigs(ConfigDesc *configDescList); + + virtual void sync(bool block); + + virtual SwapChain *createSwapChain(EGLNativeWindowType window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); + + virtual void generateSwizzle(gl::Texture *texture); + virtual void setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler); + virtual void setTexture(gl::SamplerType type, int index, gl::Texture *texture); + + virtual bool setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]); + + virtual void setRasterizerState(const gl::RasterizerState &rasterState); + virtual void setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask); + virtual void setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, + int stencilBackRef, bool frontFaceCCW); + + virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled); + virtual bool setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, + bool ignoreViewport); + + virtual bool applyPrimitiveType(GLenum mode, GLsizei count); + virtual bool applyRenderTarget(gl::Framebuffer *frameBuffer); + virtual void applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive); + virtual void applyUniforms(const gl::ProgramBinary &programBinary); + virtual GLenum applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], + GLint first, GLsizei count, GLsizei instances); + virtual GLenum applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); + virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]); + + virtual void drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive); + virtual void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); + + virtual void clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer); + + virtual void markAllStateDirty(); + + // lost device + void notifyDeviceLost(); + virtual bool isDeviceLost(); + virtual bool testDeviceLost(bool notify); + virtual bool testDeviceResettable(); + + virtual DWORD getAdapterVendor() const; + virtual std::string getRendererDescription() const; + virtual GUID getAdapterIdentifier() const; + + virtual unsigned int getMaxVertexTextureImageUnits() const; + virtual unsigned int getMaxCombinedTextureImageUnits() const; + virtual unsigned int getReservedVertexUniformVectors() const; + virtual unsigned int getReservedFragmentUniformVectors() const; + virtual unsigned int getMaxVertexUniformVectors() const; + virtual unsigned int getMaxFragmentUniformVectors() const; + virtual unsigned int getMaxVaryingVectors() const; + virtual unsigned int getMaxVertexShaderUniformBuffers() const; + virtual unsigned int getMaxFragmentShaderUniformBuffers() const; + virtual unsigned int getReservedVertexUniformBuffers() const; + virtual unsigned int getReservedFragmentUniformBuffers() const; + unsigned int getReservedVaryings() const; + virtual unsigned int getMaxTransformFeedbackBuffers() const; + virtual unsigned int getMaxTransformFeedbackSeparateComponents() const; + virtual unsigned int getMaxTransformFeedbackInterleavedComponents() const; + virtual unsigned int getMaxUniformBufferSize() const; + virtual bool getShareHandleSupport() const; + virtual bool getPostSubBufferSupport() const; + virtual int getMaxRecommendedElementsIndices() const; + virtual int getMaxRecommendedElementsVertices() const; + virtual bool getSRGBTextureSupport() const; + + virtual int getMajorShaderModel() const; + virtual int getMinSwapInterval() const; + virtual int getMaxSwapInterval() const; + + virtual GLsizei getMaxSupportedSamples() const; + virtual GLsizei getMaxSupportedFormatSamples(GLenum internalFormat) const; + virtual GLsizei getNumSampleCounts(GLenum internalFormat) const; + virtual void getSampleCounts(GLenum internalFormat, GLsizei bufSize, GLint *params) const; + int getNearestSupportedSamples(DXGI_FORMAT format, unsigned int requested) const; + + // Pixel operations + virtual bool copyToRenderTarget(TextureStorageInterface2D *dest, TextureStorageInterface2D *source); + virtual bool copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureStorageInterfaceCube *source); + virtual bool copyToRenderTarget(TextureStorageInterface3D *dest, TextureStorageInterface3D *source); + virtual bool copyToRenderTarget(TextureStorageInterface2DArray *dest, TextureStorageInterface2DArray *source); + + virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level); + virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level); + virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface3D *storage, GLint level); + virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface2DArray *storage, GLint level); + + virtual bool blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, + const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter); + virtual void readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, void* pixels); + + // RenderTarget creation + virtual RenderTarget *createRenderTarget(SwapChain *swapChain, bool depth); + virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples); + + // Shader operations + virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers); + virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround); + virtual UniformStorage *createUniformStorage(size_t storageSize); + + // Image operations + virtual Image *createImage(); + virtual void generateMipmap(Image *dest, Image *source); + virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain); + virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); + virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels); + virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); + + // Texture creation + virtual Texture2DImpl *createTexture2D(); + virtual TextureCubeImpl *createTextureCube(); + virtual Texture3DImpl *createTexture3D(); + virtual Texture2DArrayImpl *createTexture2DArray(); + + // Buffer creation + virtual BufferImpl *createBuffer(); + virtual VertexBuffer *createVertexBuffer(); + virtual IndexBuffer *createIndexBuffer(); + + // Vertex Array creation + virtual VertexArrayImpl *createVertexArray(); + + // Query and Fence creation + virtual QueryImpl *createQuery(GLenum type); + virtual FenceImpl *createFence(); + + // D3D11-renderer specific methods + ID3D11Device *getDevice() { return mDevice; } + ID3D11DeviceContext *getDeviceContext() { return mDeviceContext; }; + IDXGIFactory *getDxgiFactory() { return mDxgiFactory; }; + bool isLevel9() { return mFeatureLevel <= D3D_FEATURE_LEVEL_9_3; } + + Blit11 *getBlitter() { return mBlit; } + + // Buffer-to-texture and Texture-to-buffer copies + virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const; + virtual bool fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + + bool getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndex, ID3D11Texture2D **resource); + void unapplyRenderTargets(); + void setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView); + void packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams ¶ms, void *pixelsOut); + + virtual bool getLUID(LUID *adapterLuid) const; + virtual GLenum getNativeTextureFormat(GLenum internalFormat) const; + virtual rx::VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const; + virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const; + + private: + DISALLOW_COPY_AND_ASSIGN(Renderer11); + + virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const; + + void drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); + void drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances); + + void readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, void *pixels); + + bool blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget, + RenderTarget *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor, + bool colorBlit, bool depthBlit, bool stencilBlit); + ID3D11Texture2D *resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource); + + static void invalidateFBOAttachmentSwizzles(gl::FramebufferAttachment *attachment, int mipLevel); + static void invalidateFramebufferSwizzles(gl::Framebuffer *framebuffer); + + HMODULE mD3d11Module; + HMODULE mDxgiModule; + EGLNativeDisplayType mDc; + EGLint mRequestedDisplay; + + HLSLCompiler mCompiler; + + bool mDeviceLost; + + void initializeDevice(); + void releaseDeviceResources(); + int getMinorShaderModel() const; + void release(); + + RenderStateCache mStateCache; + + // Multisample format support + struct MultisampleSupportInfo + { + unsigned int qualityLevels[D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT]; + unsigned int maxSupportedSamples; + }; + MultisampleSupportInfo getMultisampleSupportInfo(DXGI_FORMAT format); + + typedef std::unordered_map<GLenum, MultisampleSupportInfo> MultisampleSupportMap; + MultisampleSupportMap mMultisampleSupportMap; + + unsigned int mMaxSupportedSamples; + + // current render target states + unsigned int mAppliedRenderTargetSerials[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]; + unsigned int mAppliedDepthbufferSerial; + unsigned int mAppliedStencilbufferSerial; + bool mDepthStencilInitialized; + bool mRenderTargetDescInitialized; + rx::RenderTarget::Desc mRenderTargetDesc; + + // Currently applied sampler states + bool mForceSetVertexSamplerStates[gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + gl::SamplerState mCurVertexSamplerStates[gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + + bool mForceSetPixelSamplerStates[gl::MAX_TEXTURE_IMAGE_UNITS]; + gl::SamplerState mCurPixelSamplerStates[gl::MAX_TEXTURE_IMAGE_UNITS]; + + // Currently applied textures + ID3D11ShaderResourceView *mCurVertexSRVs[gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + ID3D11ShaderResourceView *mCurPixelSRVs[gl::MAX_TEXTURE_IMAGE_UNITS]; + + // Currently applied blend state + bool mForceSetBlendState; + gl::BlendState mCurBlendState; + gl::ColorF mCurBlendColor; + unsigned int mCurSampleMask; + + // Currently applied rasterizer state + bool mForceSetRasterState; + gl::RasterizerState mCurRasterState; + + // Currently applied depth stencil state + bool mForceSetDepthStencilState; + gl::DepthStencilState mCurDepthStencilState; + int mCurStencilRef; + int mCurStencilBackRef; + + // Currently applied scissor rectangle + bool mForceSetScissor; + bool mScissorEnabled; + gl::Rectangle mCurScissor; + + // Currently applied viewport + bool mForceSetViewport; + gl::Rectangle mCurViewport; + float mCurNear; + float mCurFar; + + // Currently applied primitive topology + D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology; + + // Currently applied index buffer + ID3D11Buffer *mAppliedIB; + DXGI_FORMAT mAppliedIBFormat; + unsigned int mAppliedIBOffset; + + // Currently applied transform feedback buffers + ID3D11Buffer *mAppliedTFBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + GLintptr mAppliedTFOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + + // Currently applied shaders + ID3D11VertexShader *mAppliedVertexShader; + ID3D11GeometryShader *mAppliedGeometryShader; + ID3D11GeometryShader *mCurPointGeometryShader; + ID3D11PixelShader *mAppliedPixelShader; + + dx_VertexConstants mVertexConstants; + dx_VertexConstants mAppliedVertexConstants; + ID3D11Buffer *mDriverConstantBufferVS; + ID3D11Buffer *mCurrentVertexConstantBuffer; + unsigned int mCurrentConstantBufferVS[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS]; + + dx_PixelConstants mPixelConstants; + dx_PixelConstants mAppliedPixelConstants; + ID3D11Buffer *mDriverConstantBufferPS; + ID3D11Buffer *mCurrentPixelConstantBuffer; + unsigned int mCurrentConstantBufferPS[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS]; + + ID3D11Buffer *mCurrentGeometryConstantBuffer; + + // Vertex, index and input layouts + VertexDataManager *mVertexDataManager; + IndexDataManager *mIndexDataManager; + InputLayoutCache mInputLayoutCache; + + StreamingIndexBufferInterface *mLineLoopIB; + StreamingIndexBufferInterface *mTriangleFanIB; + + // Texture copy resources + Blit11 *mBlit; + PixelTransfer11 *mPixelTransfer; + + // Masked clear resources + Clear11 *mClear; + + // Sync query + ID3D11Query *mSyncQuery; + + ID3D11Device *mDevice; + D3D_FEATURE_LEVEL mFeatureLevel; + ID3D11DeviceContext *mDeviceContext; + IDXGIAdapter *mDxgiAdapter; + DXGI_ADAPTER_DESC mAdapterDescription; + char mDescription[128]; + IDXGIFactory *mDxgiFactory; +}; + +} +#endif // LIBGLESV2_RENDERER_RENDERER11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.cpp new file mode 100644 index 0000000000..5a7c987494 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.cpp @@ -0,0 +1,112 @@ +#include "precompiled.h" +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ShaderExecutable11.cpp: Implements a D3D11-specific class to contain shader +// executable implementation details. + +#include "libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h" + +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ + +ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11PixelShader *executable) + : ShaderExecutable(function, length) +{ + mPixelExecutable = executable; + mVertexExecutable = NULL; + mGeometryExecutable = NULL; + mStreamOutExecutable = NULL; +} + +ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut) + : ShaderExecutable(function, length) +{ + mVertexExecutable = executable; + mPixelExecutable = NULL; + mGeometryExecutable = NULL; + mStreamOutExecutable = streamOut; +} + +ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable) + : ShaderExecutable(function, length) +{ + mGeometryExecutable = executable; + mVertexExecutable = NULL; + mPixelExecutable = NULL; + mStreamOutExecutable = NULL; +} + +ShaderExecutable11::~ShaderExecutable11() +{ + SafeRelease(mVertexExecutable); + SafeRelease(mPixelExecutable); + SafeRelease(mGeometryExecutable); + SafeRelease(mStreamOutExecutable); +} + +ShaderExecutable11 *ShaderExecutable11::makeShaderExecutable11(ShaderExecutable *executable) +{ + ASSERT(HAS_DYNAMIC_TYPE(ShaderExecutable11*, executable)); + return static_cast<ShaderExecutable11*>(executable); +} + +ID3D11VertexShader *ShaderExecutable11::getVertexShader() const +{ + return mVertexExecutable; +} + +ID3D11PixelShader *ShaderExecutable11::getPixelShader() const +{ + return mPixelExecutable; +} + +ID3D11GeometryShader *ShaderExecutable11::getGeometryShader() const +{ + return mGeometryExecutable; +} + +ID3D11GeometryShader *ShaderExecutable11::getStreamOutShader() const +{ + return mStreamOutExecutable; +} + +UniformStorage11::UniformStorage11(Renderer11 *renderer, size_t initialSize) + : UniformStorage(initialSize), + mConstantBuffer(NULL) +{ + ID3D11Device *d3d11Device = renderer->getDevice(); + + if (initialSize > 0) + { + D3D11_BUFFER_DESC constantBufferDescription = {0}; + constantBufferDescription.ByteWidth = initialSize; + constantBufferDescription.Usage = D3D11_USAGE_DYNAMIC; + constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constantBufferDescription.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + constantBufferDescription.MiscFlags = 0; + constantBufferDescription.StructureByteStride = 0; + + HRESULT result = d3d11Device->CreateBuffer(&constantBufferDescription, NULL, &mConstantBuffer); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + } +} + +UniformStorage11::~UniformStorage11() +{ + SafeRelease(mConstantBuffer); +} + +const UniformStorage11 *UniformStorage11::makeUniformStorage11(const UniformStorage *uniformStorage) +{ + ASSERT(HAS_DYNAMIC_TYPE(const UniformStorage11*, uniformStorage)); + return static_cast<const UniformStorage11*>(uniformStorage); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h new file mode 100644 index 0000000000..74a1e03915 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h @@ -0,0 +1,61 @@ +// +// 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. +// + +// ShaderExecutable11.h: Defines a D3D11-specific class to contain shader +// executable implementation details. + +#ifndef LIBGLESV2_RENDERER_SHADEREXECUTABLE11_H_ +#define LIBGLESV2_RENDERER_SHADEREXECUTABLE11_H_ + +#include "libGLESv2/renderer/ShaderExecutable.h" + +namespace rx +{ +class Renderer11; +class UniformStorage11; + +class ShaderExecutable11 : public ShaderExecutable +{ + public: + ShaderExecutable11(const void *function, size_t length, ID3D11PixelShader *executable); + ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut); + ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable); + + virtual ~ShaderExecutable11(); + + static ShaderExecutable11 *makeShaderExecutable11(ShaderExecutable *executable); + + ID3D11PixelShader *getPixelShader() const; + ID3D11VertexShader *getVertexShader() const; + ID3D11GeometryShader *getGeometryShader() const; + ID3D11GeometryShader *getStreamOutShader() const; + + private: + DISALLOW_COPY_AND_ASSIGN(ShaderExecutable11); + + ID3D11PixelShader *mPixelExecutable; + ID3D11VertexShader *mVertexExecutable; + ID3D11GeometryShader *mGeometryExecutable; + ID3D11GeometryShader *mStreamOutExecutable; +}; + +class UniformStorage11 : public UniformStorage +{ + public: + UniformStorage11(Renderer11 *renderer, size_t initialSize); + virtual ~UniformStorage11(); + + static const UniformStorage11 *makeUniformStorage11(const UniformStorage *uniformStorage); + + ID3D11Buffer *getConstantBuffer() const { return mConstantBuffer; } + + private: + ID3D11Buffer *mConstantBuffer; +}; + +} + +#endif // LIBGLESV2_RENDERER_SHADEREXECUTABLE11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp new file mode 100644 index 0000000000..0341df10f9 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp @@ -0,0 +1,713 @@ +#include "precompiled.h" +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SwapChain11.cpp: Implements a back-end specific class for the D3D11 swap chain. + +#include "libGLESv2/renderer/d3d/d3d11/SwapChain11.h" + +#include "common/platform.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough2dvs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dps.h" + +namespace rx +{ + +SwapChain11::SwapChain11(Renderer11 *renderer, EGLNativeWindowType window, HANDLE shareHandle, + GLenum backBufferFormat, GLenum depthBufferFormat) + : mRenderer(renderer), SwapChain(window, shareHandle, backBufferFormat, depthBufferFormat) +{ + mSwapChain = NULL; + mBackBufferTexture = NULL; + mBackBufferRTView = NULL; + mOffscreenTexture = NULL; + mOffscreenRTView = NULL; + mOffscreenSRView = NULL; + mDepthStencilTexture = NULL; + mDepthStencilDSView = NULL; + mDepthStencilSRView = NULL; + mQuadVB = NULL; + mPassThroughSampler = NULL; + mPassThroughIL = NULL; + mPassThroughVS = NULL; + mPassThroughPS = NULL; + mWidth = -1; + mHeight = -1; + mViewportWidth = -1; + mViewportHeight = -1; + mSwapInterval = 0; + mAppCreatedShareHandle = mShareHandle != NULL; + mPassThroughResourcesInit = false; +} + +SwapChain11::~SwapChain11() +{ + release(); +} + +void SwapChain11::release() +{ + SafeRelease(mSwapChain); + SafeRelease(mBackBufferTexture); + SafeRelease(mBackBufferRTView); + SafeRelease(mOffscreenTexture); + SafeRelease(mOffscreenRTView); + SafeRelease(mOffscreenSRView); + SafeRelease(mDepthStencilTexture); + SafeRelease(mDepthStencilDSView); + SafeRelease(mDepthStencilSRView); + SafeRelease(mQuadVB); + SafeRelease(mPassThroughSampler); + SafeRelease(mPassThroughIL); + SafeRelease(mPassThroughVS); + SafeRelease(mPassThroughPS); + + if (!mAppCreatedShareHandle) + { + mShareHandle = NULL; + } +} + +void SwapChain11::releaseOffscreenTexture() +{ + SafeRelease(mOffscreenTexture); + SafeRelease(mOffscreenRTView); + SafeRelease(mOffscreenSRView); + SafeRelease(mDepthStencilTexture); + SafeRelease(mDepthStencilDSView); + SafeRelease(mDepthStencilSRView); +} + +EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHeight) +{ + ID3D11Device *device = mRenderer->getDevice(); + + ASSERT(device != NULL); + + // D3D11 does not allow zero size textures + ASSERT(backbufferWidth >= 1); + ASSERT(backbufferHeight >= 1); + +#if !defined(ANGLE_PLATFORM_WINRT) + // Preserve the render target content + ID3D11Texture2D *previousOffscreenTexture = mOffscreenTexture; + if (previousOffscreenTexture) + { + previousOffscreenTexture->AddRef(); + } + const int previousWidth = mWidth; + const int previousHeight = mHeight; +#endif + + releaseOffscreenTexture(); + + // If the app passed in a share handle, open the resource + // See EGL_ANGLE_d3d_share_handle_client_buffer + if (mAppCreatedShareHandle) + { + ID3D11Resource *tempResource11; + HRESULT result = device->OpenSharedResource(mShareHandle, __uuidof(ID3D11Resource), (void**)&tempResource11); + + if (FAILED(result)) + { + ERR("Failed to open the swap chain pbuffer share handle: %08lX", result); + release(); + return EGL_BAD_PARAMETER; + } + + result = tempResource11->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&mOffscreenTexture); + SafeRelease(tempResource11); + + if (FAILED(result)) + { + ERR("Failed to query texture2d interface in pbuffer share handle: %08lX", result); + release(); + return EGL_BAD_PARAMETER; + } + + // Validate offscreen texture parameters + D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; + mOffscreenTexture->GetDesc(&offscreenTextureDesc); + + if (offscreenTextureDesc.Width != (UINT)backbufferWidth + || offscreenTextureDesc.Height != (UINT)backbufferHeight + || offscreenTextureDesc.Format != gl_d3d11::GetTexFormat(mBackBufferFormat) + || offscreenTextureDesc.MipLevels != 1 + || offscreenTextureDesc.ArraySize != 1) + { + ERR("Invalid texture parameters in the shared offscreen texture pbuffer"); + release(); + return EGL_BAD_PARAMETER; + } + } + else + { + const bool useSharedResource = !mWindow && mRenderer->getShareHandleSupport(); + + D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; + offscreenTextureDesc.Width = backbufferWidth; + offscreenTextureDesc.Height = backbufferHeight; + offscreenTextureDesc.Format = gl_d3d11::GetTexFormat(mBackBufferFormat); + offscreenTextureDesc.MipLevels = 1; + offscreenTextureDesc.ArraySize = 1; + offscreenTextureDesc.SampleDesc.Count = 1; + offscreenTextureDesc.SampleDesc.Quality = 0; + offscreenTextureDesc.Usage = D3D11_USAGE_DEFAULT; + offscreenTextureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + offscreenTextureDesc.CPUAccessFlags = 0; + offscreenTextureDesc.MiscFlags = useSharedResource ? D3D11_RESOURCE_MISC_SHARED : 0; + + HRESULT result = device->CreateTexture2D(&offscreenTextureDesc, NULL, &mOffscreenTexture); + + if (FAILED(result)) + { + ERR("Could not create offscreen texture: %08lX", result); + release(); + + if (d3d11::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + + d3d11::SetDebugName(mOffscreenTexture, "Offscreen back buffer texture"); + + // EGL_ANGLE_surface_d3d_texture_2d_share_handle requires that we store a share handle for the client + if (useSharedResource) + { + IDXGIResource *offscreenTextureResource = NULL; + result = mOffscreenTexture->QueryInterface(__uuidof(IDXGIResource), (void**)&offscreenTextureResource); + + // Fall back to no share handle on failure + if (FAILED(result)) + { + ERR("Could not query offscreen texture resource: %08lX", result); + } + else + { + result = offscreenTextureResource->GetSharedHandle(&mShareHandle); + SafeRelease(offscreenTextureResource); + + if (FAILED(result)) + { + mShareHandle = NULL; + ERR("Could not get offscreen texture shared handle: %08lX", result); + } + } + } + } + + + D3D11_RENDER_TARGET_VIEW_DESC offscreenRTVDesc; + offscreenRTVDesc.Format = gl_d3d11::GetRTVFormat(mBackBufferFormat); + offscreenRTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + offscreenRTVDesc.Texture2D.MipSlice = 0; + + HRESULT result = device->CreateRenderTargetView(mOffscreenTexture, &offscreenRTVDesc, &mOffscreenRTView); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mOffscreenRTView, "Offscreen back buffer render target"); + + D3D11_SHADER_RESOURCE_VIEW_DESC offscreenSRVDesc; + offscreenSRVDesc.Format = gl_d3d11::GetSRVFormat(mBackBufferFormat); + offscreenSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + offscreenSRVDesc.Texture2D.MostDetailedMip = 0; + offscreenSRVDesc.Texture2D.MipLevels = -1; + + result = device->CreateShaderResourceView(mOffscreenTexture, &offscreenSRVDesc, &mOffscreenSRView); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mOffscreenSRView, "Offscreen back buffer shader resource"); + + if (mDepthBufferFormat != GL_NONE) + { + D3D11_TEXTURE2D_DESC depthStencilTextureDesc; + depthStencilTextureDesc.Width = backbufferWidth; + depthStencilTextureDesc.Height = backbufferHeight; + depthStencilTextureDesc.Format = gl_d3d11::GetTexFormat(mDepthBufferFormat); + depthStencilTextureDesc.MipLevels = 1; + depthStencilTextureDesc.ArraySize = 1; + depthStencilTextureDesc.SampleDesc.Count = 1; + depthStencilTextureDesc.SampleDesc.Quality = 0; + depthStencilTextureDesc.Usage = D3D11_USAGE_DEFAULT; + depthStencilTextureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE; + depthStencilTextureDesc.CPUAccessFlags = 0; + depthStencilTextureDesc.MiscFlags = 0; + + result = device->CreateTexture2D(&depthStencilTextureDesc, NULL, &mDepthStencilTexture); + if (FAILED(result)) + { + ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result); + release(); + + if (d3d11::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + d3d11::SetDebugName(mDepthStencilTexture, "Offscreen depth stencil texture"); + + D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilDesc; + depthStencilDesc.Format = gl_d3d11::GetDSVFormat(mDepthBufferFormat); + depthStencilDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + depthStencilDesc.Flags = 0; + depthStencilDesc.Texture2D.MipSlice = 0; + + result = device->CreateDepthStencilView(mDepthStencilTexture, &depthStencilDesc, &mDepthStencilDSView); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mDepthStencilDSView, "Offscreen depth stencil view"); + + D3D11_SHADER_RESOURCE_VIEW_DESC depthStencilSRVDesc; + depthStencilSRVDesc.Format = gl_d3d11::GetSRVFormat(mDepthBufferFormat); + depthStencilSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + depthStencilSRVDesc.Texture2D.MostDetailedMip = 0; + depthStencilSRVDesc.Texture2D.MipLevels = -1; + + result = device->CreateShaderResourceView(mDepthStencilTexture, &depthStencilSRVDesc, &mDepthStencilSRView); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mDepthStencilSRView, "Offscreen depth stencil shader resource"); + } + + mWidth = backbufferWidth; + mHeight = backbufferHeight; +#if !defined(ANGLE_PLATFORM_WINRT) || WINAPI_FAMILY==WINAPI_FAMILY_PC_APP + mViewportWidth = backbufferWidth; + mViewportHeight = backbufferHeight; +#endif + +#if !defined(ANGLE_PLATFORM_WINRT) + if (previousOffscreenTexture != NULL) + { + D3D11_BOX sourceBox = {0}; + sourceBox.left = 0; + sourceBox.right = std::min(previousWidth, mWidth); + sourceBox.top = std::max(previousHeight - mHeight, 0); + sourceBox.bottom = previousHeight; + sourceBox.front = 0; + sourceBox.back = 1; + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + const int yoffset = std::max(mHeight - previousHeight, 0); + deviceContext->CopySubresourceRegion(mOffscreenTexture, 0, 0, yoffset, 0, previousOffscreenTexture, 0, &sourceBox); + + SafeRelease(previousOffscreenTexture); + + if (mSwapChain) + { + swapRect(0, 0, mWidth, mHeight, SWAP_NORMAL); + } + } +#endif + + return EGL_SUCCESS; +} + +EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) +{ + ID3D11Device *device = mRenderer->getDevice(); + + if (device == NULL) + { + return EGL_BAD_ACCESS; + } + + // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains + if (backbufferWidth < 1 || backbufferHeight < 1) + { + return EGL_SUCCESS; + } + + // Can only call resize if we have already created our swap buffer and resources + ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView); + + SafeRelease(mBackBufferTexture); + SafeRelease(mBackBufferRTView); + + // Resize swap chain + HRESULT result; +#if !defined(ANGLE_PLATFORM_WINRT) || WINAPI_FAMILY==WINAPI_FAMILY_PC_APP // Windows phone swap chain is never resized, only the texture is +#if !defined(ANGLE_PLATFORM_WINRT) + const int bufferCount = 1; +#else + const int bufferCount = 2; +#endif + DXGI_FORMAT backbufferDXGIFormat = gl_d3d11::GetTexFormat(mBackBufferFormat); + result = mSwapChain->ResizeBuffers(bufferCount, backbufferWidth, backbufferHeight, backbufferDXGIFormat, 0); + + if (FAILED(result)) + { + ERR("Error resizing swap chain buffers: 0x%08X", result); + release(); + + if (d3d11::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } +#endif + result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture); + ASSERT(SUCCEEDED(result)); + if (SUCCEEDED(result)) + { + d3d11::SetDebugName(mBackBufferTexture, "Back buffer texture"); + } + + result = device->CreateRenderTargetView(mBackBufferTexture, NULL, &mBackBufferRTView); + ASSERT(SUCCEEDED(result)); + if (SUCCEEDED(result)) + { + d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target"); + } + + return resetOffscreenTexture(backbufferWidth, backbufferHeight); +} + +EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval) +{ + ID3D11Device *device = mRenderer->getDevice(); + + if (device == NULL) + { + return EGL_BAD_ACCESS; + } + + // 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(mBackBufferTexture); + SafeRelease(mBackBufferRTView); + + mSwapInterval = static_cast<unsigned int>(swapInterval); + if (mSwapInterval > 4) + { + // IDXGISwapChain::Present documentation states that valid sync intervals are in the [0,4] range + return EGL_BAD_PARAMETER; + } + + // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains + if (backbufferWidth < 1 || backbufferHeight < 1) + { + releaseOffscreenTexture(); + return EGL_SUCCESS; + } + + if (mWindow) + { + IDXGIFactory *factory = mRenderer->getDxgiFactory(); +#if !defined(ANGLE_PLATFORM_WINRT) + DXGI_SWAP_CHAIN_DESC swapChainDesc = {0}; + swapChainDesc.BufferDesc.Width = backbufferWidth; + swapChainDesc.BufferDesc.Height = backbufferHeight; + swapChainDesc.BufferDesc.RefreshRate.Numerator = 0; + swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; + swapChainDesc.BufferDesc.Format = gl_d3d11::GetTexFormat(mBackBufferFormat); + swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapChainDesc.BufferCount = 1; + swapChainDesc.OutputWindow = mWindow; + swapChainDesc.Windowed = TRUE; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + swapChainDesc.Flags = 0; + + HRESULT result = factory->CreateSwapChain(device, &swapChainDesc, &mSwapChain); +#else + IDXGIFactory2 *factory2; + HRESULT result = factory->QueryInterface(IID_PPV_ARGS(&factory2)); + ASSERT(SUCCEEDED(result)); + + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0}; + swapChainDesc.Width = 0; + swapChainDesc.Height = 0; + swapChainDesc.Format = gl_d3d11::GetTexFormat(mBackBufferFormat); + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapChainDesc.Stereo = FALSE; + swapChainDesc.Flags = 0; +#if WINAPI_FAMILY==WINAPI_FAMILY_PC_APP + swapChainDesc.Scaling = DXGI_SCALING_NONE; + swapChainDesc.BufferCount = 2; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; +#elif WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP + swapChainDesc.BufferCount = 1; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; +#endif + + IDXGISwapChain1 *swapChain; + result = factory2->CreateSwapChainForCoreWindow(device, mWindow, &swapChainDesc, NULL, &swapChain); + mSwapChain = swapChain; + HRESULT hr = swapChain->GetDesc1(&swapChainDesc); + ASSERT(SUCCEEDED(hr)); + mViewportWidth = swapChainDesc.Width; + mViewportHeight = swapChainDesc.Height; +#endif + + if (FAILED(result)) + { + ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result); + release(); + + if (d3d11::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + + result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mBackBufferTexture, "Back buffer texture"); + + result = device->CreateRenderTargetView(mBackBufferTexture, NULL, &mBackBufferRTView); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target"); + } + + // If we are resizing the swap chain, we don't wish to recreate all the static resources + if (!mPassThroughResourcesInit) + { + mPassThroughResourcesInit = true; + initPassThroughResources(); + } + + return resetOffscreenTexture(backbufferWidth, backbufferHeight); +} + +void SwapChain11::initPassThroughResources() +{ + ID3D11Device *device = mRenderer->getDevice(); + + ASSERT(device != NULL); + + // Make sure our resources are all not allocated, when we create + ASSERT(mQuadVB == NULL && mPassThroughSampler == NULL); + ASSERT(mPassThroughIL == NULL && mPassThroughVS == NULL && mPassThroughPS == NULL); + + D3D11_BUFFER_DESC vbDesc; + vbDesc.ByteWidth = sizeof(d3d11::PositionTexCoordVertex) * 4; + vbDesc.Usage = D3D11_USAGE_DYNAMIC; + vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + vbDesc.MiscFlags = 0; + vbDesc.StructureByteStride = 0; + + HRESULT result = device->CreateBuffer(&vbDesc, NULL, &mQuadVB); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuadVB, "Swap chain quad vertex buffer"); + + D3D11_SAMPLER_DESC samplerDesc; + samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.MipLODBias = 0.0f; + samplerDesc.MaxAnisotropy = 0; + samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + samplerDesc.BorderColor[0] = 0.0f; + samplerDesc.BorderColor[1] = 0.0f; + samplerDesc.BorderColor[2] = 0.0f; + samplerDesc.BorderColor[3] = 0.0f; + samplerDesc.MinLOD = 0; + samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; + + result = device->CreateSamplerState(&samplerDesc, &mPassThroughSampler); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mPassThroughSampler, "Swap chain pass through sampler"); + + D3D11_INPUT_ELEMENT_DESC quadLayout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + result = device->CreateInputLayout(quadLayout, 2, g_VS_Passthrough2D, sizeof(g_VS_Passthrough2D), &mPassThroughIL); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mPassThroughIL, "Swap chain pass through layout"); + + result = device->CreateVertexShader(g_VS_Passthrough2D, sizeof(g_VS_Passthrough2D), NULL, &mPassThroughVS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mPassThroughVS, "Swap chain pass through vertex shader"); + + result = device->CreatePixelShader(g_PS_PassthroughRGBA2D, sizeof(g_PS_PassthroughRGBA2D), NULL, &mPassThroughPS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mPassThroughPS, "Swap chain pass through pixel shader"); +} + +// parameters should be validated/clamped by caller +EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint flags) +{ + if (!mSwapChain) + { + return EGL_SUCCESS; + } + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + // Set vertices + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = deviceContext->Map(mQuadVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return EGL_BAD_ACCESS; + } + + d3d11::PositionTexCoordVertex *vertices = static_cast<d3d11::PositionTexCoordVertex*>(mappedResource.pData); + + // Create a quad in homogeneous coordinates + float x1 = (x / float(mWidth)) * 2.0f - 1.0f; + float y1 = (y / float(mHeight)) * 2.0f - 1.0f; + float x2 = ((x + width) / float(mWidth)) * 2.0f - 1.0f; + float y2 = ((y + height) / float(mHeight)) * 2.0f - 1.0f; + + float u1 = x / float(mWidth); + float v1 = y / float(mHeight); + float u2 = (x + width) / float(mWidth); + float v2 = (y + height) / float(mHeight); + + const int rotateL = flags & SWAP_ROTATE_90; + const int rotateR = flags & SWAP_ROTATE_270; + + d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, rotateL ? u2 : u1, rotateR ? v2 : v1); + d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, rotateR ? u2 : u1, rotateL ? v1 : v2); + d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, rotateR ? u1 : u2, rotateL ? v2 : v1); + d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, rotateL ? u1 : u2, rotateR ? v1 : v2); + + deviceContext->Unmap(mQuadVB, 0); + + static UINT stride = sizeof(d3d11::PositionTexCoordVertex); + static UINT startIdx = 0; + deviceContext->IASetVertexBuffers(0, 1, &mQuadVB, &stride, &startIdx); + + // Apply state + deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); + + static const float blendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + deviceContext->OMSetBlendState(NULL, blendFactor, 0xFFFFFFF); + + deviceContext->RSSetState(NULL); + + // Apply shaders + deviceContext->IASetInputLayout(mPassThroughIL); + deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + deviceContext->VSSetShader(mPassThroughVS, NULL, 0); + deviceContext->PSSetShader(mPassThroughPS, NULL, 0); + deviceContext->GSSetShader(NULL, NULL, 0); + + // Apply render targets + mRenderer->setOneTimeRenderTarget(mBackBufferRTView); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = mViewportWidth; + viewport.Height = mViewportHeight; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + // Apply textures + deviceContext->PSSetShaderResources(0, 1, &mOffscreenSRView); + deviceContext->PSSetSamplers(0, 1, &mPassThroughSampler); + + // Draw + deviceContext->Draw(4, 0); + +#if ANGLE_FORCE_VSYNC_OFF + result = mSwapChain->Present(0, 0); +#else + result = mSwapChain->Present(mSwapInterval, 0); +#endif + + if (result == DXGI_ERROR_DEVICE_REMOVED) + { + HRESULT removedReason = device->GetDeviceRemovedReason(); + UNUSED_TRACE_VARIABLE(removedReason); + ERR("Present failed: the D3D11 device was removed: 0x%08X", removedReason); + return EGL_CONTEXT_LOST; + } + else if (result == DXGI_ERROR_DEVICE_RESET) + { + ERR("Present failed: the D3D11 device was reset from a bad command."); + return EGL_CONTEXT_LOST; + } + else if (FAILED(result)) + { + ERR("Present failed with error code 0x%08X", result); + } + + // Unbind + static ID3D11ShaderResourceView *const nullSRV = NULL; + deviceContext->PSSetShaderResources(0, 1, &nullSRV); + + mRenderer->unapplyRenderTargets(); + mRenderer->markAllStateDirty(); + + return EGL_SUCCESS; +} + +ID3D11Texture2D *SwapChain11::getOffscreenTexture() +{ + return mOffscreenTexture; +} + +ID3D11RenderTargetView *SwapChain11::getRenderTarget() +{ + return mOffscreenRTView; +} + +ID3D11ShaderResourceView *SwapChain11::getRenderTargetShaderResource() +{ + return mOffscreenSRView; +} + +ID3D11DepthStencilView *SwapChain11::getDepthStencil() +{ + return mDepthStencilDSView; +} + +ID3D11ShaderResourceView * SwapChain11::getDepthStencilShaderResource() +{ + return mDepthStencilSRView; +} + +ID3D11Texture2D *SwapChain11::getDepthStencilTexture() +{ + return mDepthStencilTexture; +} + +SwapChain11 *SwapChain11::makeSwapChain11(SwapChain *swapChain) +{ + ASSERT(HAS_DYNAMIC_TYPE(rx::SwapChain11*, swapChain)); + return static_cast<rx::SwapChain11*>(swapChain); +} + +void SwapChain11::recreate() +{ + // possibly should use this method instead of reset +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h new file mode 100644 index 0000000000..b30b78568a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h @@ -0,0 +1,82 @@ +// +// 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. +// + +// SwapChain11.h: Defines a back-end specific class for the D3D11 swap chain. + +#ifndef LIBGLESV2_RENDERER_SWAPCHAIN11_H_ +#define LIBGLESV2_RENDERER_SWAPCHAIN11_H_ + +#include "common/angleutils.h" +#include "libGLESv2/renderer/SwapChain.h" + +namespace rx +{ +class Renderer11; + +class SwapChain11 : public SwapChain +{ + public: + SwapChain11(Renderer11 *renderer, EGLNativeWindowType window, HANDLE shareHandle, + GLenum backBufferFormat, GLenum depthBufferFormat); + virtual ~SwapChain11(); + + EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight); + virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval); + virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint flags); + virtual void recreate(); + + virtual ID3D11Texture2D *getOffscreenTexture(); + virtual ID3D11RenderTargetView *getRenderTarget(); + virtual ID3D11ShaderResourceView *getRenderTargetShaderResource(); + + virtual ID3D11Texture2D *getDepthStencilTexture(); + virtual ID3D11DepthStencilView *getDepthStencil(); + virtual ID3D11ShaderResourceView *getDepthStencilShaderResource(); + + EGLint getWidth() const { return mWidth; } + EGLint getHeight() const { return mHeight; } + + static SwapChain11 *makeSwapChain11(SwapChain *swapChain); + + private: + DISALLOW_COPY_AND_ASSIGN(SwapChain11); + + void release(); + void initPassThroughResources(); + void releaseOffscreenTexture(); + EGLint resetOffscreenTexture(int backbufferWidth, int backbufferHeight); + + Renderer11 *mRenderer; + EGLint mHeight; + EGLint mWidth; + EGLint mViewportWidth; + EGLint mViewportHeight; + bool mAppCreatedShareHandle; + unsigned int mSwapInterval; + bool mPassThroughResourcesInit; + + IDXGISwapChain *mSwapChain; + + ID3D11Texture2D *mBackBufferTexture; + ID3D11RenderTargetView *mBackBufferRTView; + + ID3D11Texture2D *mOffscreenTexture; + ID3D11RenderTargetView *mOffscreenRTView; + ID3D11ShaderResourceView *mOffscreenSRView; + + ID3D11Texture2D *mDepthStencilTexture; + ID3D11DepthStencilView *mDepthStencilDSView; + ID3D11ShaderResourceView *mDepthStencilSRView; + + ID3D11Buffer *mQuadVB; + ID3D11SamplerState *mPassThroughSampler; + ID3D11InputLayout *mPassThroughIL; + ID3D11VertexShader *mPassThroughVS; + ID3D11PixelShader *mPassThroughPS; +}; + +} +#endif // LIBGLESV2_RENDERER_SWAPCHAIN11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp new file mode 100644 index 0000000000..00b81b7c92 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp @@ -0,0 +1,1559 @@ +#include "precompiled.h" +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureStorage11.cpp: Implements the abstract rx::TextureStorage11 class and its concrete derived +// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 texture. + +#include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h" + +#include "libGLESv2/renderer/d3d/TextureD3D.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" +#include "libGLESv2/renderer/d3d/d3d11/SwapChain11.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/Blit11.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" + +#include "common/utilities.h" +#include "libGLESv2/main.h" + +namespace rx +{ + +TextureStorage11::SwizzleCacheValue::SwizzleCacheValue() + : swizzleRed(GL_NONE), swizzleGreen(GL_NONE), swizzleBlue(GL_NONE), swizzleAlpha(GL_NONE) +{ +} + +TextureStorage11::SwizzleCacheValue::SwizzleCacheValue(GLenum red, GLenum green, GLenum blue, GLenum alpha) + : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha) +{ +} + +bool TextureStorage11::SwizzleCacheValue::operator==(const SwizzleCacheValue &other) const +{ + return swizzleRed == other.swizzleRed && + swizzleGreen == other.swizzleGreen && + swizzleBlue == other.swizzleBlue && + swizzleAlpha == other.swizzleAlpha; +} + +bool TextureStorage11::SwizzleCacheValue::operator!=(const SwizzleCacheValue &other) const +{ + return !(*this == other); +} + +TextureStorage11::SRVKey::SRVKey(int baseLevel, int mipLevels, bool swizzle) + : baseLevel(baseLevel), mipLevels(mipLevels), swizzle(swizzle) +{ +} + +bool TextureStorage11::SRVKey::operator==(const SRVKey &rhs) const +{ + return baseLevel == rhs.baseLevel && + mipLevels == rhs.mipLevels && + swizzle == rhs.swizzle; +} + +TextureStorage11::SRVCache::~SRVCache() +{ + for (size_t i = 0; i < cache.size(); i++) + { + SafeRelease(cache[i].srv); + } +} + +ID3D11ShaderResourceView *TextureStorage11::SRVCache::find(const SRVKey &key) const +{ + for (size_t i = 0; i < cache.size(); i++) + { + if (cache[i].key == key) + { + return cache[i].srv; + } + } + + return NULL; +} + +ID3D11ShaderResourceView *TextureStorage11::SRVCache::add(const SRVKey &key, ID3D11ShaderResourceView *srv) +{ + SRVPair pair = {key, srv}; + cache.push_back(pair); + + return srv; +} + +TextureStorage11::TextureStorage11(Renderer *renderer, UINT bindFlags) + : mBindFlags(bindFlags), + mTopLevel(0), + mMipLevels(0), + mTextureFormat(DXGI_FORMAT_UNKNOWN), + mShaderResourceFormat(DXGI_FORMAT_UNKNOWN), + mRenderTargetFormat(DXGI_FORMAT_UNKNOWN), + mDepthStencilFormat(DXGI_FORMAT_UNKNOWN), + mTextureWidth(0), + mTextureHeight(0), + mTextureDepth(0) +{ + mRenderer = Renderer11::makeRenderer11(renderer); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mLevelSRVs[i] = NULL; + } +} + +TextureStorage11::~TextureStorage11() +{ + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + SafeRelease(mLevelSRVs[level]); + } +} + +TextureStorage11 *TextureStorage11::makeTextureStorage11(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11*, storage)); + return static_cast<TextureStorage11*>(storage); +} + +DWORD TextureStorage11::GetTextureBindFlags(GLenum internalFormat, bool renderTarget) +{ + UINT bindFlags = 0; + + if (gl_d3d11::GetSRVFormat(internalFormat) != DXGI_FORMAT_UNKNOWN) + { + bindFlags |= D3D11_BIND_SHADER_RESOURCE; + } + if (gl_d3d11::GetDSVFormat(internalFormat) != DXGI_FORMAT_UNKNOWN) + { + bindFlags |= D3D11_BIND_DEPTH_STENCIL; + } + if (gl_d3d11::GetRTVFormat(internalFormat) != DXGI_FORMAT_UNKNOWN && renderTarget) + { + bindFlags |= D3D11_BIND_RENDER_TARGET; + } + + return bindFlags; +} + +UINT TextureStorage11::getBindFlags() const +{ + return mBindFlags; +} + +int TextureStorage11::getTopLevel() const +{ + return mTopLevel; +} + +bool TextureStorage11::isRenderTarget() const +{ + return (mBindFlags & (D3D11_BIND_RENDER_TARGET | D3D11_BIND_DEPTH_STENCIL)) != 0; +} + +bool TextureStorage11::isManaged() const +{ + return false; +} + +int TextureStorage11::getLevelCount() const +{ + return mMipLevels - mTopLevel; +} + +int TextureStorage11::getLevelWidth(int mipLevel) const +{ + return std::max(static_cast<int>(mTextureWidth) >> mipLevel, 1); +} + +int TextureStorage11::getLevelHeight(int mipLevel) const +{ + return std::max(static_cast<int>(mTextureHeight) >> mipLevel, 1); +} + +int TextureStorage11::getLevelDepth(int mipLevel) const +{ + return std::max(static_cast<int>(mTextureDepth) >> mipLevel, 1); +} + +UINT TextureStorage11::getSubresourceIndex(int mipLevel, int layerTarget) const +{ + UINT index = 0; + if (getResource()) + { + index = D3D11CalcSubresource(mipLevel, layerTarget, mMipLevels); + } + return index; +} + +ID3D11ShaderResourceView *TextureStorage11::getSRV(const gl::SamplerState &samplerState) +{ + bool swizzleRequired = samplerState.swizzleRequired(); + bool mipmapping = IsMipmapFiltered(samplerState); + unsigned int mipLevels = mipmapping ? (samplerState.maxLevel - samplerState.baseLevel) : 1; + + // Make sure there's 'mipLevels' mipmap levels below the base level (offset by the top level, which corresponds to GL level 0) + mipLevels = std::min(mipLevels, mMipLevels - mTopLevel - samplerState.baseLevel); + + if (swizzleRequired) + { + verifySwizzleExists(samplerState.swizzleRed, samplerState.swizzleGreen, samplerState.swizzleBlue, samplerState.swizzleAlpha); + } + + SRVKey key(samplerState.baseLevel, mipLevels, swizzleRequired); + ID3D11ShaderResourceView *srv = srvCache.find(key); + + if(srv) + { + return srv; + } + + DXGI_FORMAT format = (swizzleRequired ? mSwizzleShaderResourceFormat : mShaderResourceFormat); + ID3D11Resource *texture = swizzleRequired ? getSwizzleTexture() : getResource(); + + srv = createSRV(samplerState.baseLevel, mipLevels, format, texture); + + return srvCache.add(key, srv); +} + +ID3D11ShaderResourceView *TextureStorage11::getSRVLevel(int mipLevel) +{ + if (mipLevel >= 0 && mipLevel < getLevelCount()) + { + if (!mLevelSRVs[mipLevel]) + { + mLevelSRVs[mipLevel] = createSRV(mipLevel, 1, mShaderResourceFormat, getResource()); + } + + return mLevelSRVs[mipLevel]; + } + else + { + return NULL; + } +} + +void TextureStorage11::generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) +{ + SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); + for (int level = 0; level < getLevelCount(); level++) + { + // Check if the swizzle for this level is out of date + if (mSwizzleCache[level] != swizzleTarget) + { + // Need to re-render the swizzle for this level + ID3D11ShaderResourceView *sourceSRV = getSRVLevel(level); + ID3D11RenderTargetView *destRTV = getSwizzleRenderTarget(level); + + gl::Extents size(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); + + Blit11 *blitter = mRenderer->getBlitter(); + + if (blitter->swizzleTexture(sourceSRV, destRTV, size, swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha)) + { + mSwizzleCache[level] = swizzleTarget; + } + else + { + ERR("Failed to swizzle texture."); + } + } + } +} + +void TextureStorage11::invalidateSwizzleCacheLevel(int mipLevel) +{ + if (mipLevel >= 0 && static_cast<unsigned int>(mipLevel) < ArraySize(mSwizzleCache)) + { + // The default constructor of SwizzleCacheValue has GL_NONE for all channels which is not a + // valid swizzle combination + mSwizzleCache[mipLevel] = SwizzleCacheValue(); + } +} + +void TextureStorage11::invalidateSwizzleCache() +{ + for (unsigned int mipLevel = 0; mipLevel < ArraySize(mSwizzleCache); mipLevel++) + { + invalidateSwizzleCacheLevel(mipLevel); + } +} + +bool TextureStorage11::updateSubresourceLevel(ID3D11Resource *srcTexture, unsigned int sourceSubresource, + int level, int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth) +{ + if (srcTexture) + { + invalidateSwizzleCacheLevel(level); + + gl::Extents texSize(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); + gl::Box copyArea(xoffset, yoffset, zoffset, width, height, depth); + + bool fullCopy = copyArea.x == 0 && + copyArea.y == 0 && + copyArea.z == 0 && + copyArea.width == texSize.width && + copyArea.height == texSize.height && + copyArea.depth == texSize.depth; + + ID3D11Resource *dstTexture = getResource(); + unsigned int dstSubresource = getSubresourceIndex(level + mTopLevel, layerTarget); + + ASSERT(dstTexture); + + if (!fullCopy && (d3d11::GetDepthBits(mTextureFormat) > 0 || d3d11::GetStencilBits(mTextureFormat) > 0)) + { + // CopySubresourceRegion cannot copy partial depth stencils, use the blitter instead + Blit11 *blitter = mRenderer->getBlitter(); + + return blitter->copyDepthStencil(srcTexture, sourceSubresource, copyArea, texSize, + dstTexture, dstSubresource, copyArea, texSize, + NULL); + } + else + { + D3D11_BOX srcBox; + srcBox.left = copyArea.x; + srcBox.top = copyArea.y; + srcBox.right = copyArea.x + roundUp((unsigned int)width, d3d11::GetBlockWidth(mTextureFormat)); + srcBox.bottom = copyArea.y + roundUp((unsigned int)height, d3d11::GetBlockHeight(mTextureFormat)); + srcBox.front = copyArea.z; + srcBox.back = copyArea.z + copyArea.depth; + + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + context->CopySubresourceRegion(dstTexture, dstSubresource, copyArea.x, copyArea.y, copyArea.z, + srcTexture, sourceSubresource, fullCopy ? NULL : &srcBox); + return true; + } + } + + return false; +} + +void TextureStorage11::generateMipmapLayer(RenderTarget11 *source, RenderTarget11 *dest) +{ + if (source && dest) + { + ID3D11ShaderResourceView *sourceSRV = source->getShaderResourceView(); + ID3D11RenderTargetView *destRTV = dest->getRenderTargetView(); + + if (sourceSRV && destRTV) + { + gl::Box sourceArea(0, 0, 0, source->getWidth(), source->getHeight(), source->getDepth()); + gl::Extents sourceSize(source->getWidth(), source->getHeight(), source->getDepth()); + + gl::Box destArea(0, 0, 0, dest->getWidth(), dest->getHeight(), dest->getDepth()); + gl::Extents destSize(dest->getWidth(), dest->getHeight(), dest->getDepth()); + + Blit11 *blitter = mRenderer->getBlitter(); + + blitter->copyTexture(sourceSRV, sourceArea, sourceSize, destRTV, destArea, destSize, NULL, + gl::GetFormat(source->getInternalFormat()), GL_LINEAR); + } + } +} + +void TextureStorage11::verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) +{ + SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); + for (unsigned int level = 0; level < mMipLevels; level++) + { + ASSERT(mSwizzleCache[level] == swizzleTarget); + } +} + +TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapchain) + : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE) +{ + mTexture = swapchain->getOffscreenTexture(); + mTexture->AddRef(); + mSwizzleTexture = NULL; + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mRenderTarget[i] = NULL; + mSwizzleRenderTargets[i] = NULL; + } + + D3D11_TEXTURE2D_DESC texDesc; + mTexture->GetDesc(&texDesc); + mMipLevels = texDesc.MipLevels; + mTextureFormat = texDesc.Format; + mTextureWidth = texDesc.Width; + mTextureHeight = texDesc.Height; + mTextureDepth = 1; + + ID3D11ShaderResourceView *srv = swapchain->getRenderTargetShaderResource(); + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srv->GetDesc(&srvDesc); + mShaderResourceFormat = srvDesc.Format; + + ID3D11RenderTargetView* offscreenRTV = swapchain->getRenderTarget(); + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + offscreenRTV->GetDesc(&rtvDesc); + mRenderTargetFormat = rtvDesc.Format; + + GLenum internalFormat = d3d11_gl::GetInternalFormat(mTextureFormat); + mSwizzleTextureFormat = gl_d3d11::GetSwizzleTexFormat(internalFormat); + mSwizzleShaderResourceFormat = gl_d3d11::GetSwizzleSRVFormat(internalFormat); + mSwizzleRenderTargetFormat = gl_d3d11::GetSwizzleRTVFormat(internalFormat); + + mDepthStencilFormat = DXGI_FORMAT_UNKNOWN; +} + +TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) + : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderTarget)) +{ + mTexture = NULL; + mSwizzleTexture = NULL; + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mRenderTarget[i] = NULL; + mSwizzleRenderTargets[i] = NULL; + } + + mTextureFormat = gl_d3d11::GetTexFormat(internalformat); + mShaderResourceFormat = gl_d3d11::GetSRVFormat(internalformat); + mDepthStencilFormat = gl_d3d11::GetDSVFormat(internalformat); + mRenderTargetFormat = gl_d3d11::GetRTVFormat(internalformat); + mSwizzleTextureFormat = gl_d3d11::GetSwizzleTexFormat(internalformat); + mSwizzleShaderResourceFormat = gl_d3d11::GetSwizzleSRVFormat(internalformat); + mSwizzleRenderTargetFormat = gl_d3d11::GetSwizzleRTVFormat(internalformat); + + // if the width or height is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (width > 0 && height > 0) + { + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; // Compressed texture size constraints? + desc.Height = height; + desc.MipLevels = mRenderer->isLevel9() ? 1 : ((levels > 0) ? (mTopLevel + levels) : 0); + desc.ArraySize = 1; + desc.Format = mTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + gl::error(GL_OUT_OF_MEMORY); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + ERR("Creating image failed."); + gl::error(GL_OUT_OF_MEMORY); + } + else + { + mTexture->GetDesc(&desc); + mMipLevels = desc.MipLevels; + mTextureWidth = desc.Width; + mTextureHeight = desc.Height; + mTextureDepth = 1; + } + } +} + +TextureStorage11_2D::~TextureStorage11_2D() +{ + SafeRelease(mTexture); + SafeRelease(mSwizzleTexture); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + SafeDelete(mRenderTarget[i]); + SafeRelease(mSwizzleRenderTargets[i]); + } +} + +TextureStorage11_2D *TextureStorage11_2D::makeTextureStorage11_2D(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2D*, storage)); + return static_cast<TextureStorage11_2D*>(storage); +} + +ID3D11Resource *TextureStorage11_2D::getResource() const +{ + return mTexture; +} + +RenderTarget *TextureStorage11_2D::getRenderTarget(int level) +{ + if (level >= 0 && level < getLevelCount()) + { + if (!mRenderTarget[level]) + { + ID3D11ShaderResourceView *srv = getSRVLevel(level); + if (!srv) + { + return NULL; + } + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mTopLevel + level; + + ID3D11RenderTargetView *rtv; + HRESULT result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + mRenderTarget[level] = new RenderTarget11(mRenderer, rtv, mTexture, srv, getLevelWidth(level), getLevelHeight(level), 1); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + } + else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mDepthStencilFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + dsvDesc.Texture2D.MipSlice = mTopLevel + level; + dsvDesc.Flags = 0; + + ID3D11DepthStencilView *dsv; + HRESULT result = device->CreateDepthStencilView(mTexture, &dsvDesc, &dsv); + + if (result == E_OUTOFMEMORY) + { + SafeRelease(srv); + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + mRenderTarget[level] = new RenderTarget11(mRenderer, dsv, mTexture, srv, getLevelWidth(level), getLevelHeight(level), 1); + + // RenderTarget will take ownership of these resources + SafeRelease(dsv); + } + else + { + UNREACHABLE(); + } + } + + return mRenderTarget[level]; + } + else + { + return NULL; + } +} + +ID3D11ShaderResourceView *TextureStorage11_2D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture) +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MostDetailedMip = mTopLevel + baseLevel; + srvDesc.Texture2D.MipLevels = mipLevels; + + ID3D11ShaderResourceView *SRV = NULL; + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, &SRV); + + if (result == E_OUTOFMEMORY) + { + gl::error(GL_OUT_OF_MEMORY); + } + ASSERT(SUCCEEDED(result)); + + return SRV; +} + +void TextureStorage11_2D::generateMipmap(int level) +{ + invalidateSwizzleCacheLevel(level); + + RenderTarget11 *source = RenderTarget11::makeRenderTarget11(getRenderTarget(level - 1)); + RenderTarget11 *dest = RenderTarget11::makeRenderTarget11(getRenderTarget(level)); + + generateMipmapLayer(source, dest); +} + +ID3D11Resource *TextureStorage11_2D::getSwizzleTexture() +{ + if (!mSwizzleTexture) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = 1; + desc.Format = mSwizzleTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11Texture2D*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + } + + return mSwizzleTexture; +} + +ID3D11RenderTargetView *TextureStorage11_2D::getSwizzleRenderTarget(int mipLevel) +{ + if (mipLevel >= 0 && mipLevel < getLevelCount()) + { + if (!mSwizzleRenderTargets[mipLevel]) + { + ID3D11Resource *swizzleTexture = getSwizzleTexture(); + if (!swizzleTexture) + { + return NULL; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mTopLevel + mipLevel; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11RenderTargetView*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + } + + return mSwizzleRenderTargets[mipLevel]; + } + else + { + return NULL; + } +} + +unsigned int TextureStorage11_2D::getTextureLevelDepth(int mipLevel) const +{ + return 1; +} + +TextureStorage11_Cube::TextureStorage11_Cube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels) + : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderTarget)) +{ + mTexture = NULL; + mSwizzleTexture = NULL; + + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mSwizzleRenderTargets[level] = NULL; + for (unsigned int face = 0; face < 6; face++) + { + mRenderTarget[face][level] = NULL; + } + } + + mTextureFormat = gl_d3d11::GetTexFormat(internalformat); + mShaderResourceFormat = gl_d3d11::GetSRVFormat(internalformat); + mDepthStencilFormat = gl_d3d11::GetDSVFormat(internalformat); + mRenderTargetFormat = gl_d3d11::GetRTVFormat(internalformat); + mSwizzleTextureFormat = gl_d3d11::GetSwizzleTexFormat(internalformat); + mSwizzleShaderResourceFormat = gl_d3d11::GetSwizzleSRVFormat(internalformat); + mSwizzleRenderTargetFormat = gl_d3d11::GetSwizzleRTVFormat(internalformat); + + // if the size is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (size > 0) + { + // adjust size if needed for compressed textures + int height = size; + d3d11::MakeValidSize(false, mTextureFormat, &size, &height, &mTopLevel); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = size; + desc.Height = size; + desc.MipLevels = ((levels > 0) ? (mTopLevel + levels) : 0); + desc.ArraySize = 6; + desc.Format = mTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); + + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + ERR("Creating image failed."); + gl::error(GL_OUT_OF_MEMORY); + } + else + { + mTexture->GetDesc(&desc); + mMipLevels = desc.MipLevels; + mTextureWidth = desc.Width; + mTextureHeight = desc.Height; + mTextureDepth = 1; + } + } +} + +TextureStorage11_Cube::~TextureStorage11_Cube() +{ + SafeRelease(mTexture); + SafeRelease(mSwizzleTexture); + + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + SafeRelease(mSwizzleRenderTargets[level]); + for (unsigned int face = 0; face < 6; face++) + { + SafeDelete(mRenderTarget[face][level]); + } + } +} + +TextureStorage11_Cube *TextureStorage11_Cube::makeTextureStorage11_Cube(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_Cube*, storage)); + return static_cast<TextureStorage11_Cube*>(storage); +} + +ID3D11Resource *TextureStorage11_Cube::getResource() const +{ + return mTexture; +} + +RenderTarget *TextureStorage11_Cube::getRenderTargetFace(GLenum faceTarget, int level) +{ + if (level >= 0 && level < getLevelCount()) + { + int faceIndex = TextureD3D_Cube::targetToIndex(faceTarget); + if (!mRenderTarget[faceIndex][level]) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = mShaderResourceFormat; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; // Will be used with Texture2D sampler, not TextureCube + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + level; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = faceIndex; + srvDesc.Texture2DArray.ArraySize = 1; + + ID3D11ShaderResourceView *srv; + result = device->CreateShaderResourceView(mTexture, &srvDesc, &srv); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; + rtvDesc.Texture2DArray.FirstArraySlice = faceIndex; + rtvDesc.Texture2DArray.ArraySize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); + + if (result == E_OUTOFMEMORY) + { + SafeRelease(srv); + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + mRenderTarget[faceIndex][level] = new RenderTarget11(mRenderer, rtv, mTexture, srv, getLevelWidth(level), getLevelHeight(level), 1); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + SafeRelease(srv); + } + else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mDepthStencilFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + dsvDesc.Flags = 0; + dsvDesc.Texture2DArray.MipSlice = mTopLevel + level; + dsvDesc.Texture2DArray.FirstArraySlice = faceIndex; + dsvDesc.Texture2DArray.ArraySize = 1; + + ID3D11DepthStencilView *dsv; + result = device->CreateDepthStencilView(mTexture, &dsvDesc, &dsv); + + if (result == E_OUTOFMEMORY) + { + SafeRelease(srv); + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + mRenderTarget[faceIndex][level] = new RenderTarget11(mRenderer, dsv, mTexture, srv, getLevelWidth(level), getLevelHeight(level), 1); + + // RenderTarget will take ownership of these resources + SafeRelease(dsv); + SafeRelease(srv); + } + else + { + UNREACHABLE(); + } + } + + return mRenderTarget[faceIndex][level]; + } + else + { + return NULL; + } +} + +ID3D11ShaderResourceView *TextureStorage11_Cube::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture) +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + + // Unnormalized integer cube maps are not supported by DX11; we emulate them as an array of six 2D textures + bool unnormalizedInteger = (d3d11::GetComponentType(mTextureFormat) == GL_INT || + d3d11::GetComponentType(mTextureFormat) == GL_UNSIGNED_INT); + + if(unnormalizedInteger) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = 0; + srvDesc.Texture2DArray.ArraySize = 6; + } + else + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + srvDesc.TextureCube.MipLevels = mipLevels; + srvDesc.TextureCube.MostDetailedMip = mTopLevel + baseLevel; + } + + ID3D11ShaderResourceView *SRV = NULL; + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, &SRV); + + if (result == E_OUTOFMEMORY) + { + gl::error(GL_OUT_OF_MEMORY); + } + ASSERT(SUCCEEDED(result)); + + return SRV; +} + +void TextureStorage11_Cube::generateMipmap(int faceIndex, int level) +{ + invalidateSwizzleCacheLevel(level); + + RenderTarget11 *source = RenderTarget11::makeRenderTarget11(getRenderTargetFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level - 1)); + RenderTarget11 *dest = RenderTarget11::makeRenderTarget11(getRenderTargetFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level)); + + generateMipmapLayer(source, dest); +} + +ID3D11Resource *TextureStorage11_Cube::getSwizzleTexture() +{ + if (!mSwizzleTexture) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = 6; + desc.Format = mSwizzleTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11Texture2D*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + } + + return mSwizzleTexture; +} + +ID3D11RenderTargetView *TextureStorage11_Cube::getSwizzleRenderTarget(int mipLevel) +{ + if (mipLevel >= 0 && mipLevel < getLevelCount()) + { + if (!mSwizzleRenderTargets[mipLevel]) + { + ID3D11Resource *swizzleTexture = getSwizzleTexture(); + if (!swizzleTexture) + { + return NULL; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture2DArray.FirstArraySlice = 0; + rtvDesc.Texture2DArray.ArraySize = 6; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11RenderTargetView*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + } + + return mSwizzleRenderTargets[mipLevel]; + } + else + { + return NULL; + } +} + +unsigned int TextureStorage11_Cube::getTextureLevelDepth(int mipLevel) const +{ + return 6; +} + +TextureStorage11_3D::TextureStorage11_3D(Renderer *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels) + : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderTarget)) +{ + mTexture = NULL; + mSwizzleTexture = NULL; + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mLevelRenderTargets[i] = NULL; + mSwizzleRenderTargets[i] = NULL; + } + + mTextureFormat = gl_d3d11::GetTexFormat(internalformat); + mShaderResourceFormat = gl_d3d11::GetSRVFormat(internalformat); + mDepthStencilFormat = gl_d3d11::GetDSVFormat(internalformat); + mRenderTargetFormat = gl_d3d11::GetRTVFormat(internalformat); + mSwizzleTextureFormat = gl_d3d11::GetSwizzleTexFormat(internalformat); + mSwizzleShaderResourceFormat = gl_d3d11::GetSwizzleSRVFormat(internalformat); + mSwizzleRenderTargetFormat = gl_d3d11::GetSwizzleRTVFormat(internalformat); + + // If the width, height or depth are not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (width > 0 && height > 0 && depth > 0) + { + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE3D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.Depth = depth; + desc.MipLevels = ((levels > 0) ? (mTopLevel + levels) : 0); + desc.Format = mTextureFormat; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture3D(&desc, NULL, &mTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + gl::error(GL_OUT_OF_MEMORY); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + ERR("Creating image failed."); + gl::error(GL_OUT_OF_MEMORY); + } + else + { + mTexture->GetDesc(&desc); + mMipLevels = desc.MipLevels; + mTextureWidth = desc.Width; + mTextureHeight = desc.Height; + mTextureDepth = desc.Depth; + } + } +} + +TextureStorage11_3D::~TextureStorage11_3D() +{ + SafeRelease(mTexture); + SafeRelease(mSwizzleTexture); + + for (RenderTargetMap::iterator i = mLevelLayerRenderTargets.begin(); i != mLevelLayerRenderTargets.end(); i++) + { + SafeDelete(i->second); + } + mLevelLayerRenderTargets.clear(); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + SafeDelete(mLevelRenderTargets[i]); + SafeRelease(mSwizzleRenderTargets[i]); + } +} + +TextureStorage11_3D *TextureStorage11_3D::makeTextureStorage11_3D(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_3D*, storage)); + return static_cast<TextureStorage11_3D*>(storage); +} + +ID3D11Resource *TextureStorage11_3D::getResource() const +{ + return mTexture; +} + +ID3D11ShaderResourceView *TextureStorage11_3D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture) +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; + srvDesc.Texture3D.MostDetailedMip = baseLevel; + srvDesc.Texture3D.MipLevels = mipLevels; + + ID3D11ShaderResourceView *SRV = NULL; + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, &SRV); + + if (result == E_OUTOFMEMORY) + { + gl::error(GL_OUT_OF_MEMORY); + } + ASSERT(SUCCEEDED(result)); + + return SRV; +} + +RenderTarget *TextureStorage11_3D::getRenderTarget(int mipLevel) +{ + if (mipLevel >= 0 && mipLevel < getLevelCount()) + { + if (!mLevelRenderTargets[mipLevel]) + { + ID3D11ShaderResourceView *srv = getSRVLevel(mipLevel); + if (!srv) + { + return NULL; + } + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = 0; + rtvDesc.Texture3D.WSize = -1; + + ID3D11RenderTargetView *rtv; + HRESULT result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); + + if (result == E_OUTOFMEMORY) + { + SafeRelease(srv); + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + mLevelRenderTargets[mipLevel] = new RenderTarget11(mRenderer, rtv, mTexture, srv, getLevelWidth(mipLevel), getLevelHeight(mipLevel), getLevelDepth(mipLevel)); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + } + else + { + UNREACHABLE(); + } + } + + return mLevelRenderTargets[mipLevel]; + } + else + { + return NULL; + } +} + +RenderTarget *TextureStorage11_3D::getRenderTargetLayer(int mipLevel, int layer) +{ + if (mipLevel >= 0 && mipLevel < getLevelCount()) + { + LevelLayerKey key(mipLevel, layer); + if (mLevelLayerRenderTargets.find(key) == mLevelLayerRenderTargets.end()) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + // TODO, what kind of SRV is expected here? + ID3D11ShaderResourceView *srv = NULL; + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = layer; + rtvDesc.Texture3D.WSize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); + + if (result == E_OUTOFMEMORY) + { + SafeRelease(srv); + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + mLevelLayerRenderTargets[key] = new RenderTarget11(mRenderer, rtv, mTexture, srv, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + SafeRelease(srv); + } + else + { + UNREACHABLE(); + } + } + + return mLevelLayerRenderTargets[key]; + } + else + { + return NULL; + } +} + +void TextureStorage11_3D::generateMipmap(int level) +{ + invalidateSwizzleCacheLevel(level); + + RenderTarget11 *source = RenderTarget11::makeRenderTarget11(getRenderTarget(level - 1)); + RenderTarget11 *dest = RenderTarget11::makeRenderTarget11(getRenderTarget(level)); + + generateMipmapLayer(source, dest); +} + +ID3D11Resource *TextureStorage11_3D::getSwizzleTexture() +{ + if (!mSwizzleTexture) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE3D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.Depth = mTextureDepth; + desc.MipLevels = mMipLevels; + desc.Format = mSwizzleTextureFormat; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture3D(&desc, NULL, &mSwizzleTexture); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11Texture3D*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + } + + return mSwizzleTexture; +} + +ID3D11RenderTargetView *TextureStorage11_3D::getSwizzleRenderTarget(int mipLevel) +{ + if (mipLevel >= 0 && mipLevel < getLevelCount()) + { + if (!mSwizzleRenderTargets[mipLevel]) + { + ID3D11Resource *swizzleTexture = getSwizzleTexture(); + if (!swizzleTexture) + { + return NULL; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = 0; + rtvDesc.Texture3D.WSize = -1; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11RenderTargetView*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + } + + return mSwizzleRenderTargets[mipLevel]; + } + else + { + return NULL; + } +} + +unsigned int TextureStorage11_3D::getTextureLevelDepth(int mipLevel) const +{ + return std::max(mTextureDepth >> mipLevel, 1U); +} + + +TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels) + : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderTarget)) +{ + mTexture = NULL; + mSwizzleTexture = NULL; + + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mSwizzleRenderTargets[level] = NULL; + } + + mTextureFormat = gl_d3d11::GetTexFormat(internalformat); + mShaderResourceFormat = gl_d3d11::GetSRVFormat(internalformat); + mDepthStencilFormat = gl_d3d11::GetDSVFormat(internalformat); + mRenderTargetFormat = gl_d3d11::GetRTVFormat(internalformat); + mSwizzleTextureFormat = gl_d3d11::GetSwizzleTexFormat(internalformat); + mSwizzleShaderResourceFormat = gl_d3d11::GetSwizzleSRVFormat(internalformat); + mSwizzleRenderTargetFormat = gl_d3d11::GetSwizzleRTVFormat(internalformat); + + // if the width, height or depth is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (width > 0 && height > 0 && depth > 0) + { + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.MipLevels = ((levels > 0) ? (mTopLevel + levels) : 0); + desc.ArraySize = depth; + desc.Format = mTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + gl::error(GL_OUT_OF_MEMORY); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + ERR("Creating image failed."); + gl::error(GL_OUT_OF_MEMORY); + } + else + { + mTexture->GetDesc(&desc); + mMipLevels = desc.MipLevels; + mTextureWidth = desc.Width; + mTextureHeight = desc.Height; + mTextureDepth = desc.ArraySize; + } + } +} + +TextureStorage11_2DArray::~TextureStorage11_2DArray() +{ + SafeRelease(mTexture); + SafeRelease(mSwizzleTexture); + + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + SafeRelease(mSwizzleRenderTargets[level]); + } + + for (RenderTargetMap::iterator i = mRenderTargets.begin(); i != mRenderTargets.end(); i++) + { + SafeDelete(i->second); + } + mRenderTargets.clear(); +} + +TextureStorage11_2DArray *TextureStorage11_2DArray::makeTextureStorage11_2DArray(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2DArray*, storage)); + return static_cast<TextureStorage11_2DArray*>(storage); +} + +ID3D11Resource *TextureStorage11_2DArray::getResource() const +{ + return mTexture; +} + +ID3D11ShaderResourceView *TextureStorage11_2DArray::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture) +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; + srvDesc.Texture2DArray.MipLevels = mipLevels; + srvDesc.Texture2DArray.FirstArraySlice = 0; + srvDesc.Texture2DArray.ArraySize = mTextureDepth; + + ID3D11ShaderResourceView *SRV = NULL; + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, &SRV); + + if (result == E_OUTOFMEMORY) + { + gl::error(GL_OUT_OF_MEMORY); + } + ASSERT(SUCCEEDED(result)); + + return SRV; +} + +RenderTarget *TextureStorage11_2DArray::getRenderTargetLayer(int mipLevel, int layer) +{ + if (mipLevel >= 0 && mipLevel < getLevelCount()) + { + LevelLayerKey key(mipLevel, layer); + if (mRenderTargets.find(key) == mRenderTargets.end()) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = mShaderResourceFormat; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + mipLevel; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = layer; + srvDesc.Texture2DArray.ArraySize = 1; + + ID3D11ShaderResourceView *srv; + result = device->CreateShaderResourceView(mTexture, &srvDesc, &srv); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture2DArray.FirstArraySlice = layer; + rtvDesc.Texture2DArray.ArraySize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); + + if (result == E_OUTOFMEMORY) + { + SafeRelease(srv); + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + mRenderTargets[key] = new RenderTarget11(mRenderer, rtv, mTexture, srv, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + SafeRelease(srv); + } + else + { + UNREACHABLE(); + } + } + + return mRenderTargets[key]; + } + else + { + return NULL; + } +} + +void TextureStorage11_2DArray::generateMipmap(int level) +{ + invalidateSwizzleCacheLevel(level); + for (unsigned int layer = 0; layer < mTextureDepth; layer++) + { + RenderTarget11 *source = RenderTarget11::makeRenderTarget11(getRenderTargetLayer(level - 1, layer)); + RenderTarget11 *dest = RenderTarget11::makeRenderTarget11(getRenderTargetLayer(level, layer)); + + generateMipmapLayer(source, dest); + } +} + +ID3D11Resource *TextureStorage11_2DArray::getSwizzleTexture() +{ + if (!mSwizzleTexture) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = mTextureDepth; + desc.Format = mSwizzleTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11Texture2D*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + } + + return mSwizzleTexture; +} + +ID3D11RenderTargetView *TextureStorage11_2DArray::getSwizzleRenderTarget(int mipLevel) +{ + if (mipLevel >= 0 && mipLevel < getLevelCount()) + { + if (!mSwizzleRenderTargets[mipLevel]) + { + ID3D11Resource *swizzleTexture = getSwizzleTexture(); + if (!swizzleTexture) + { + return NULL; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture2DArray.FirstArraySlice = 0; + rtvDesc.Texture2DArray.ArraySize = mTextureDepth; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11RenderTargetView*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + } + + return mSwizzleRenderTargets[mipLevel]; + } + else + { + return NULL; + } +} + +unsigned int TextureStorage11_2DArray::getTextureLevelDepth(int mipLevel) const +{ + return mTextureDepth; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h new file mode 100644 index 0000000000..6be7bac8e2 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h @@ -0,0 +1,278 @@ +// +// 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. +// + +// TextureStorage11.h: Defines the abstract rx::TextureStorage11 class and its concrete derived +// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 texture. + +#ifndef LIBGLESV2_RENDERER_TEXTURESTORAGE11_H_ +#define LIBGLESV2_RENDERER_TEXTURESTORAGE11_H_ + +#include "libGLESv2/Texture.h" +#include "libGLESv2/renderer/d3d/TextureStorage.h" + +namespace rx +{ +class RenderTarget; +class RenderTarget11; +class Renderer; +class Renderer11; +class SwapChain11; + +class TextureStorage11 : public TextureStorage +{ + public: + virtual ~TextureStorage11(); + + static TextureStorage11 *makeTextureStorage11(TextureStorage *storage); + + static DWORD GetTextureBindFlags(GLenum internalFormat, bool renderTarget); + + UINT getBindFlags() const; + + virtual ID3D11Resource *getResource() const = 0; + virtual ID3D11ShaderResourceView *getSRV(const gl::SamplerState &samplerState); + virtual RenderTarget *getRenderTarget(int level) { return NULL; } + virtual RenderTarget *getRenderTargetFace(GLenum faceTarget, int level) { return NULL; } + virtual RenderTarget *getRenderTargetLayer(int mipLevel, int layer) { return NULL; } + + virtual void generateMipmap(int level) {}; + virtual void generateMipmap(int face, int level) {}; + + virtual int getTopLevel() const; + virtual bool isRenderTarget() const; + virtual bool isManaged() const; + virtual int getLevelCount() const; + UINT getSubresourceIndex(int mipLevel, int layerTarget) const; + + void generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); + void invalidateSwizzleCacheLevel(int mipLevel); + void invalidateSwizzleCache(); + + bool updateSubresourceLevel(ID3D11Resource *texture, unsigned int sourceSubresource, int level, + int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth); + + protected: + TextureStorage11(Renderer *renderer, UINT bindFlags); + void generateMipmapLayer(RenderTarget11 *source, RenderTarget11 *dest); + int getLevelWidth(int mipLevel) const; + int getLevelHeight(int mipLevel) const; + int getLevelDepth(int mipLevel) const; + + virtual ID3D11Resource *getSwizzleTexture() = 0; + virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel) = 0; + ID3D11ShaderResourceView *getSRVLevel(int mipLevel); + + virtual ID3D11ShaderResourceView *createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture) = 0; + + void verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); + + virtual unsigned int getTextureLevelDepth(int mipLevel) const = 0; + + Renderer11 *mRenderer; + int mTopLevel; + unsigned int mMipLevels; + + DXGI_FORMAT mTextureFormat; + DXGI_FORMAT mShaderResourceFormat; + DXGI_FORMAT mRenderTargetFormat; + DXGI_FORMAT mDepthStencilFormat; + DXGI_FORMAT mSwizzleTextureFormat; + DXGI_FORMAT mSwizzleShaderResourceFormat; + DXGI_FORMAT mSwizzleRenderTargetFormat; + unsigned int mTextureWidth; + unsigned int mTextureHeight; + unsigned int mTextureDepth; + + struct SwizzleCacheValue + { + GLenum swizzleRed; + GLenum swizzleGreen; + GLenum swizzleBlue; + GLenum swizzleAlpha; + + SwizzleCacheValue(); + SwizzleCacheValue(GLenum red, GLenum green, GLenum blue, GLenum alpha); + + bool operator ==(const SwizzleCacheValue &other) const; + bool operator !=(const SwizzleCacheValue &other) const; + }; + SwizzleCacheValue mSwizzleCache[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + struct SRVKey + { + SRVKey(int baseLevel = 0, int mipLevels = 0, bool swizzle = false); + + bool operator==(const SRVKey &rhs) const; + + int baseLevel; + int mipLevels; + bool swizzle; + }; + + struct SRVPair + { + SRVKey key; + ID3D11ShaderResourceView *srv; + }; + + struct SRVCache + { + ~SRVCache(); + + ID3D11ShaderResourceView *find(const SRVKey &key) const; + ID3D11ShaderResourceView *add(const SRVKey &key, ID3D11ShaderResourceView *srv); + + std::vector<SRVPair> cache; + }; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage11); + + const UINT mBindFlags; + + SRVCache srvCache; + ID3D11ShaderResourceView *mLevelSRVs[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureStorage11_2D : public TextureStorage11 +{ + public: + TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapchain); + TextureStorage11_2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); + virtual ~TextureStorage11_2D(); + + static TextureStorage11_2D *makeTextureStorage11_2D(TextureStorage *storage); + + virtual ID3D11Resource *getResource() const; + virtual RenderTarget *getRenderTarget(int level); + + virtual void generateMipmap(int level); + + protected: + virtual ID3D11Resource *getSwizzleTexture(); + virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); + + virtual unsigned int getTextureLevelDepth(int mipLevel) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage11_2D); + + virtual ID3D11ShaderResourceView *createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture); + + ID3D11Texture2D *mTexture; + RenderTarget11 *mRenderTarget[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + ID3D11Texture2D *mSwizzleTexture; + ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureStorage11_Cube : public TextureStorage11 +{ + public: + TextureStorage11_Cube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels); + virtual ~TextureStorage11_Cube(); + + static TextureStorage11_Cube *makeTextureStorage11_Cube(TextureStorage *storage); + + virtual ID3D11Resource *getResource() const; + virtual RenderTarget *getRenderTargetFace(GLenum faceTarget, int level); + + virtual void generateMipmap(int faceIndex, int level); + + protected: + virtual ID3D11Resource *getSwizzleTexture(); + virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); + + virtual unsigned int getTextureLevelDepth(int mipLevel) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage11_Cube); + + virtual ID3D11ShaderResourceView *createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture); + + ID3D11Texture2D *mTexture; + RenderTarget11 *mRenderTarget[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + ID3D11Texture2D *mSwizzleTexture; + ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureStorage11_3D : public TextureStorage11 +{ + public: + TextureStorage11_3D(Renderer *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual ~TextureStorage11_3D(); + + static TextureStorage11_3D *makeTextureStorage11_3D(TextureStorage *storage); + + virtual ID3D11Resource *getResource() const; + virtual RenderTarget *getRenderTarget(int mipLevel); + virtual RenderTarget *getRenderTargetLayer(int mipLevel, int layer); + + virtual void generateMipmap(int level); + + protected: + virtual ID3D11Resource *getSwizzleTexture(); + virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); + + virtual unsigned int getTextureLevelDepth(int mipLevel) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage11_3D); + + virtual ID3D11ShaderResourceView *createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture); + + typedef std::pair<int, int> LevelLayerKey; + typedef std::map<LevelLayerKey, RenderTarget11*> RenderTargetMap; + RenderTargetMap mLevelLayerRenderTargets; + + RenderTarget11 *mLevelRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + ID3D11Texture3D *mTexture; + ID3D11Texture3D *mSwizzleTexture; + ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureStorage11_2DArray : public TextureStorage11 +{ + public: + TextureStorage11_2DArray(Renderer *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual ~TextureStorage11_2DArray(); + + static TextureStorage11_2DArray *makeTextureStorage11_2DArray(TextureStorage *storage); + + virtual ID3D11Resource *getResource() const; + virtual RenderTarget *getRenderTargetLayer(int mipLevel, int layer); + + virtual void generateMipmap(int level); + + protected: + virtual ID3D11Resource *getSwizzleTexture(); + virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); + + virtual unsigned int getTextureLevelDepth(int mipLevel) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage11_2DArray); + + virtual ID3D11ShaderResourceView *createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture); + + typedef std::pair<int, int> LevelLayerKey; + typedef std::map<LevelLayerKey, RenderTarget11*> RenderTargetMap; + RenderTargetMap mRenderTargets; + + ID3D11Texture2D *mTexture; + + ID3D11Texture2D *mSwizzleTexture; + ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +} + +#endif // LIBGLESV2_RENDERER_TEXTURESTORAGE11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexArray11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexArray11.h new file mode 100644 index 0000000000..590cb9f05a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexArray11.h @@ -0,0 +1,42 @@ +// +// 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. +// + +// VertexArray11.h: Defines the rx::VertexArray11 class which implements rx::VertexArrayImpl. + +#ifndef LIBGLESV2_RENDERER_VERTEXARRAY11_H_ +#define LIBGLESV2_RENDERER_VERTEXARRAY11_H_ + +#include "libGLESv2/renderer/VertexArrayImpl.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ +class Renderer11; + +class VertexArray11 : public VertexArrayImpl +{ + public: + VertexArray11(rx::Renderer11 *renderer) + : VertexArrayImpl(), + mRenderer(renderer) + { + } + virtual ~VertexArray11() { } + + virtual void setElementArrayBuffer(const gl::Buffer *buffer) { } + virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) { } + virtual void setAttributeDivisor(size_t idx, GLuint divisor) { } + virtual void enableAttribute(size_t idx, bool enabledState) { } + + private: + DISALLOW_COPY_AND_ASSIGN(VertexArray11); + + rx::Renderer11 *mRenderer; +}; + +} + +#endif // LIBGLESV2_RENDERER_VERTEXARRAY11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.cpp new file mode 100644 index 0000000000..2f47ec0a67 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.cpp @@ -0,0 +1,223 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexBuffer11.cpp: Defines the D3D11 VertexBuffer implementation. + +#include "libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h" +#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" + +#include "libGLESv2/Buffer.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" + +namespace rx +{ + +VertexBuffer11::VertexBuffer11(rx::Renderer11 *const renderer) : mRenderer(renderer) +{ + mBuffer = NULL; + mBufferSize = 0; + mDynamicUsage = false; +} + +VertexBuffer11::~VertexBuffer11() +{ + SafeRelease(mBuffer); +} + +bool VertexBuffer11::initialize(unsigned int size, bool dynamicUsage) +{ + SafeRelease(mBuffer); + + updateSerial(); + + if (size > 0) + { + ID3D11Device* dxDevice = mRenderer->getDevice(); + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = size; + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + + HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); + if (FAILED(result)) + { + return false; + } + } + + mBufferSize = size; + mDynamicUsage = dynamicUsage; + return true; +} + +VertexBuffer11 *VertexBuffer11::makeVertexBuffer11(VertexBuffer *vetexBuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer11*, vetexBuffer)); + return static_cast<VertexBuffer11*>(vetexBuffer); +} + +bool VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset) +{ + if (mBuffer) + { + gl::Buffer *buffer = attrib.buffer.get(); + int inputStride = ComputeVertexAttributeStride(attrib); + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); + if (FAILED(result)) + { + ERR("Vertex buffer map failed with error 0x%08x", result); + return false; + } + + char* output = reinterpret_cast<char*>(mappedResource.pData) + offset; + + const char *input = NULL; + if (attrib.enabled) + { + if (buffer) + { + Buffer11 *storage = Buffer11::makeBuffer11(buffer->getImplementation()); + input = static_cast<const char*>(storage->getData()) + static_cast<int>(attrib.offset); + } + else + { + input = static_cast<const char*>(attrib.pointer); + } + } + else + { + input = reinterpret_cast<const char*>(currentValue.FloatValues); + } + + if (instances == 0 || attrib.divisor == 0) + { + input += inputStride * start; + } + + gl::VertexFormat vertexFormat(attrib, currentValue.Type); + VertexCopyFunction conversionFunc = gl_d3d11::GetVertexCopyFunction(vertexFormat); + ASSERT(conversionFunc != NULL); + conversionFunc(input, inputStride, count, output); + + dxContext->Unmap(mBuffer, 0); + + return true; + } + else + { + ERR("Vertex buffer not initialized."); + return false; + } +} + +bool VertexBuffer11::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, + GLsizei instances, unsigned int *outSpaceRequired) const +{ + unsigned int elementCount = 0; + if (attrib.enabled) + { + if (instances == 0 || attrib.divisor == 0) + { + elementCount = count; + } + else + { + if (static_cast<unsigned int>(instances) < std::numeric_limits<unsigned int>::max() - (attrib.divisor - 1)) + { + // Round up + elementCount = rx::roundUp(static_cast<unsigned int>(instances), attrib.divisor); + } + else + { + elementCount = instances / attrib.divisor; + } + } + + gl::VertexFormat vertexFormat(attrib); + unsigned int elementSize = static_cast<unsigned int>(gl_d3d11::GetVertexElementSize(vertexFormat)); + if (elementSize <= std::numeric_limits<unsigned int>::max() / elementCount) + { + if (outSpaceRequired) + { + *outSpaceRequired = elementSize * elementCount; + } + return true; + } + else + { + return false; + } + } + else + { + const unsigned int elementSize = 4; + if (outSpaceRequired) + { + *outSpaceRequired = elementSize * 4; + } + return true; + } +} + +unsigned int VertexBuffer11::getBufferSize() const +{ + return mBufferSize; +} + +bool VertexBuffer11::setBufferSize(unsigned int size) +{ + if (size > mBufferSize) + { + return initialize(size, mDynamicUsage); + } + else + { + return true; + } +} + +bool VertexBuffer11::discard() +{ + if (mBuffer) + { + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + ERR("Vertex buffer map failed with error 0x%08x", result); + return false; + } + + dxContext->Unmap(mBuffer, 0); + + return true; + } + else + { + ERR("Vertex buffer not initialized."); + return false; + } +} + +ID3D11Buffer *VertexBuffer11::getBuffer() const +{ + return mBuffer; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h new file mode 100644 index 0000000000..c2a5aa7afd --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h @@ -0,0 +1,52 @@ +// +// 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. +// + +// VertexBuffer11.h: Defines the D3D11 VertexBuffer implementation. + +#ifndef LIBGLESV2_RENDERER_VERTEXBUFFER11_H_ +#define LIBGLESV2_RENDERER_VERTEXBUFFER11_H_ + +#include "libGLESv2/renderer/d3d/VertexBuffer.h" + +namespace rx +{ +class Renderer11; + +class VertexBuffer11 : public VertexBuffer +{ + public: + explicit VertexBuffer11(rx::Renderer11 *const renderer); + virtual ~VertexBuffer11(); + + virtual bool initialize(unsigned int size, bool dynamicUsage); + + static VertexBuffer11 *makeVertexBuffer11(VertexBuffer *vetexBuffer); + + virtual bool storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset); + + virtual bool getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, + unsigned int *outSpaceRequired) const; + + virtual unsigned int getBufferSize() const; + virtual bool setBufferSize(unsigned int size); + virtual bool discard(); + + ID3D11Buffer *getBuffer() const; + + private: + DISALLOW_COPY_AND_ASSIGN(VertexBuffer11); + + rx::Renderer11 *const mRenderer; + + ID3D11Buffer *mBuffer; + unsigned int mBufferSize; + bool mDynamicUsage; +}; + +} + +#endif // LIBGLESV2_RENDERER_VERTEXBUFFER11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp new file mode 100644 index 0000000000..c991fd4991 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp @@ -0,0 +1,1458 @@ +#include "precompiled.h" +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils11.cpp: Queries for GL image formats and their translations to D3D11 +// formats. + +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" +#include "libGLESv2/renderer/generatemip.h" +#include "libGLESv2/renderer/loadimage.h" +#include "libGLESv2/renderer/copyimage.h" +#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/renderer/copyvertex.h" + +namespace rx +{ + +struct D3D11FormatInfo +{ + DXGI_FORMAT mTexFormat; + DXGI_FORMAT mSRVFormat; + DXGI_FORMAT mRTVFormat; + DXGI_FORMAT mDSVFormat; + + D3D11FormatInfo() + : mTexFormat(DXGI_FORMAT_UNKNOWN), mDSVFormat(DXGI_FORMAT_UNKNOWN), mRTVFormat(DXGI_FORMAT_UNKNOWN), mSRVFormat(DXGI_FORMAT_UNKNOWN) + { } + + D3D11FormatInfo(DXGI_FORMAT texFormat, DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat, DXGI_FORMAT dsvFormat) + : mTexFormat(texFormat), mDSVFormat(dsvFormat), mRTVFormat(rtvFormat), mSRVFormat(srvFormat) + { } +}; + +// For sized GL internal formats, there is only one corresponding D3D11 format. This map type allows +// querying for the DXGI texture formats to use for textures, SRVs, RTVs and DSVs given a GL internal +// format. +typedef std::pair<GLenum, D3D11FormatInfo> D3D11ES3FormatPair; +typedef std::map<GLenum, D3D11FormatInfo> D3D11ES3FormatMap; + +static D3D11ES3FormatMap BuildD3D11FormatMap() +{ + D3D11ES3FormatMap map; + + // | GL internal format | | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | + map.insert(D3D11ES3FormatPair(GL_NONE, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R8, D3D11FormatInfo(DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R8_SNORM, D3D11FormatInfo(DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG8, D3D11FormatInfo(DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG8_SNORM, D3D11FormatInfo(DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB8, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB8_SNORM, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB565, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA4, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB5_A1, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA8, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA8_SNORM, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB10_A2, D3D11FormatInfo(DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB10_A2UI, D3D11FormatInfo(DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_SRGB8, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_SRGB8_ALPHA8, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R16F, D3D11FormatInfo(DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG16F, D3D11FormatInfo(DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB16F, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA16F, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R32F, D3D11FormatInfo(DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG32F, D3D11FormatInfo(DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB32F, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA32F, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R11F_G11F_B10F, D3D11FormatInfo(DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB9_E5, D3D11FormatInfo(DXGI_FORMAT_R9G9B9E5_SHAREDEXP, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R8I, D3D11FormatInfo(DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R8UI, D3D11FormatInfo(DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R16I, D3D11FormatInfo(DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R16UI, D3D11FormatInfo(DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R32I, D3D11FormatInfo(DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R32UI, D3D11FormatInfo(DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG8I, D3D11FormatInfo(DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG8UI, D3D11FormatInfo(DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG16I, D3D11FormatInfo(DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG16UI, D3D11FormatInfo(DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG32I, D3D11FormatInfo(DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG32UI, D3D11FormatInfo(DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB8I, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB8UI, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB16I, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB16UI, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB32I, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB32UI, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA8I, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA8UI, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA16I, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA16UI, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA32I, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA32UI, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_UNKNOWN))); + + // Unsized formats, TODO: Are types of float and half float allowed for the unsized types? Would it change the DXGI format? + map.insert(D3D11ES3FormatPair(GL_ALPHA, D3D11FormatInfo(DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_LUMINANCE, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_LUMINANCE_ALPHA, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_BGRA_EXT, D3D11FormatInfo(DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + + // From GL_EXT_texture_storage + // | GL internal format | | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | + map.insert(D3D11ES3FormatPair(GL_ALPHA8_EXT, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_LUMINANCE8_EXT, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_ALPHA32F_EXT, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_LUMINANCE32F_EXT, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_ALPHA16F_EXT, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_LUMINANCE16F_EXT, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_LUMINANCE8_ALPHA8_EXT, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_LUMINANCE_ALPHA32F_EXT, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_LUMINANCE_ALPHA16F_EXT, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_BGRA8_EXT, D3D11FormatInfo(DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_BGRA4_ANGLEX, D3D11FormatInfo(DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_BGR5_A1_ANGLEX, D3D11FormatInfo(DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN ))); + + // Depth stencil formats + map.insert(D3D11ES3FormatPair(GL_DEPTH_COMPONENT16, D3D11FormatInfo(DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D16_UNORM ))); + map.insert(D3D11ES3FormatPair(GL_DEPTH_COMPONENT24, D3D11FormatInfo(DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ))); + map.insert(D3D11ES3FormatPair(GL_DEPTH_COMPONENT32F, D3D11FormatInfo(DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D32_FLOAT ))); + map.insert(D3D11ES3FormatPair(GL_DEPTH24_STENCIL8, D3D11FormatInfo(DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ))); + map.insert(D3D11ES3FormatPair(GL_DEPTH32F_STENCIL8, D3D11FormatInfo(DXGI_FORMAT_R32G8X24_TYPELESS, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D32_FLOAT_S8X24_UINT))); + map.insert(D3D11ES3FormatPair(GL_STENCIL_INDEX8, D3D11FormatInfo(DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_X24_TYPELESS_G8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ))); + + // From GL_ANGLE_depth_texture + // Since D3D11 doesn't have a D32_UNORM format, use D24S8 which has comparable precision and matches the ES3 format. + map.insert(D3D11ES3FormatPair(GL_DEPTH_COMPONENT32_OES, D3D11FormatInfo(DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ))); + + // Compressed formats, From ES 3.0.1 spec, table 3.16 + // | GL internal format | | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_R11_EAC, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_SIGNED_R11_EAC, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_RG11_EAC, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_SIGNED_RG11_EAC, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_RGB8_ETC2, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_SRGB8_ETC2, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_RGBA8_ETC2_EAC, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + + // From GL_EXT_texture_compression_dxt1 + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, D3D11FormatInfo(DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, D3D11FormatInfo(DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + + // From GL_ANGLE_texture_compression_dxt3 + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, D3D11FormatInfo(DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + + // From GL_ANGLE_texture_compression_dxt5 + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, D3D11FormatInfo(DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + + return map; +} + +static bool GetD3D11FormatInfo(GLenum internalFormat, D3D11FormatInfo *outFormatInfo) +{ + static const D3D11ES3FormatMap formatMap = BuildD3D11FormatMap(); + D3D11ES3FormatMap::const_iterator iter = formatMap.find(internalFormat); + if (iter != formatMap.end()) + { + if (outFormatInfo) + { + *outFormatInfo = iter->second; + } + return true; + } + else + { + return false; + } +} + +// ES3 image loading functions vary based on the internal format and data type given, +// this map type determines the loading function from the internal format and type supplied +// to glTex*Image*D and the destination DXGI_FORMAT. Source formats and types are taken from +// Tables 3.2 and 3.3 of the ES 3 spec. +typedef std::pair<GLenum, GLenum> InternalFormatTypePair; +typedef std::pair<InternalFormatTypePair, LoadImageFunction> D3D11LoadFunctionPair; +typedef std::map<InternalFormatTypePair, LoadImageFunction> D3D11LoadFunctionMap; + +static void UnimplementedLoadFunction(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) +{ + UNIMPLEMENTED(); +} + +static void UnreachableLoadFunction(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(); +} + +// A helper function to insert data into the D3D11LoadFunctionMap with fewer characters. +static inline void insertLoadFunction(D3D11LoadFunctionMap *map, GLenum internalFormat, GLenum type, + LoadImageFunction loadFunc) +{ + map->insert(D3D11LoadFunctionPair(InternalFormatTypePair(internalFormat, type), loadFunc)); +} + +D3D11LoadFunctionMap buildD3D11LoadFunctionMap() +{ + D3D11LoadFunctionMap map; + + // | Internal format | Type | Load function | + insertLoadFunction(&map, GL_RGBA8, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> ); + insertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> ); + insertLoadFunction(&map, GL_RGBA4, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> ); + insertLoadFunction(&map, GL_SRGB8_ALPHA8, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> ); + insertLoadFunction(&map, GL_RGBA8_SNORM, GL_BYTE, LoadToNative<GLbyte, 4> ); + insertLoadFunction(&map, GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4, LoadRGBA4ToRGBA8 ); + insertLoadFunction(&map, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, LoadToNative<GLuint, 1> ); + insertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_SHORT_5_5_5_1, LoadRGB5A1ToRGBA8 ); + insertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_INT_2_10_10_10_REV, LoadRGB10A2ToRGBA8 ); + insertLoadFunction(&map, GL_RGBA16F, GL_HALF_FLOAT, LoadToNative<GLhalf, 4> ); + insertLoadFunction(&map, GL_RGBA16F, GL_HALF_FLOAT_OES, LoadToNative<GLhalf, 4> ); + insertLoadFunction(&map, GL_RGBA32F, GL_FLOAT, LoadToNative<GLfloat, 4> ); + insertLoadFunction(&map, GL_RGBA16F, GL_FLOAT, Load32FTo16F<4> ); + insertLoadFunction(&map, GL_RGBA8UI, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> ); + insertLoadFunction(&map, GL_RGBA8I, GL_BYTE, LoadToNative<GLbyte, 4> ); + insertLoadFunction(&map, GL_RGBA16UI, GL_UNSIGNED_SHORT, LoadToNative<GLushort, 4> ); + insertLoadFunction(&map, GL_RGBA16I, GL_SHORT, LoadToNative<GLshort, 4> ); + insertLoadFunction(&map, GL_RGBA32UI, GL_UNSIGNED_INT, LoadToNative<GLuint, 4> ); + insertLoadFunction(&map, GL_RGBA32I, GL_INT, LoadToNative<GLint, 4> ); + insertLoadFunction(&map, GL_RGB10_A2UI, GL_UNSIGNED_INT_2_10_10_10_REV, LoadToNative<GLuint, 1> ); + insertLoadFunction(&map, GL_RGB8, GL_UNSIGNED_BYTE, LoadToNative3To4<GLubyte, 0xFF> ); + insertLoadFunction(&map, GL_RGB565, GL_UNSIGNED_BYTE, LoadToNative3To4<GLubyte, 0xFF> ); + insertLoadFunction(&map, GL_SRGB8, GL_UNSIGNED_BYTE, LoadToNative3To4<GLubyte, 0xFF> ); + insertLoadFunction(&map, GL_RGB8_SNORM, GL_BYTE, LoadToNative3To4<GLbyte, 0x7F> ); + insertLoadFunction(&map, GL_RGB565, GL_UNSIGNED_SHORT_5_6_5, LoadR5G6B5ToRGBA8 ); + insertLoadFunction(&map, GL_R11F_G11F_B10F, GL_UNSIGNED_INT_10F_11F_11F_REV, LoadToNative<GLuint, 1> ); + insertLoadFunction(&map, GL_RGB9_E5, GL_UNSIGNED_INT_5_9_9_9_REV, LoadToNative<GLuint, 1> ); + insertLoadFunction(&map, GL_RGB16F, GL_HALF_FLOAT, LoadToNative3To4<GLhalf, gl::Float16One>); + insertLoadFunction(&map, GL_RGB16F, GL_HALF_FLOAT_OES, LoadToNative3To4<GLhalf, gl::Float16One>); + insertLoadFunction(&map, GL_R11F_G11F_B10F, GL_HALF_FLOAT, LoadRGB16FToRG11B10F ); + insertLoadFunction(&map, GL_R11F_G11F_B10F, GL_HALF_FLOAT_OES, LoadRGB16FToRG11B10F ); + insertLoadFunction(&map, GL_RGB9_E5, GL_HALF_FLOAT, LoadRGB16FToRGB9E5 ); + insertLoadFunction(&map, GL_RGB9_E5, GL_HALF_FLOAT_OES, LoadRGB16FToRGB9E5 ); + insertLoadFunction(&map, GL_RGB32F, GL_FLOAT, LoadToNative3To4<GLfloat, gl::Float32One>); + insertLoadFunction(&map, GL_RGB16F, GL_FLOAT, LoadRGB32FToRGBA16F ); + insertLoadFunction(&map, GL_R11F_G11F_B10F, GL_FLOAT, LoadRGB32FToRG11B10F ); + insertLoadFunction(&map, GL_RGB9_E5, GL_FLOAT, LoadRGB32FToRGB9E5 ); + insertLoadFunction(&map, GL_RGB8UI, GL_UNSIGNED_BYTE, LoadToNative3To4<GLubyte, 0x01> ); + insertLoadFunction(&map, GL_RGB8I, GL_BYTE, LoadToNative3To4<GLbyte, 0x01> ); + insertLoadFunction(&map, GL_RGB16UI, GL_UNSIGNED_SHORT, LoadToNative3To4<GLushort, 0x0001> ); + insertLoadFunction(&map, GL_RGB16I, GL_SHORT, LoadToNative3To4<GLshort, 0x0001> ); + insertLoadFunction(&map, GL_RGB32UI, GL_UNSIGNED_INT, LoadToNative3To4<GLuint, 0x00000001> ); + insertLoadFunction(&map, GL_RGB32I, GL_INT, LoadToNative3To4<GLint, 0x00000001> ); + insertLoadFunction(&map, GL_RG8, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 2> ); + insertLoadFunction(&map, GL_RG8_SNORM, GL_BYTE, LoadToNative<GLbyte, 2> ); + insertLoadFunction(&map, GL_RG16F, GL_HALF_FLOAT, LoadToNative<GLhalf, 2> ); + insertLoadFunction(&map, GL_RG16F, GL_HALF_FLOAT_OES, LoadToNative<GLhalf, 2> ); + insertLoadFunction(&map, GL_RG32F, GL_FLOAT, LoadToNative<GLfloat, 2> ); + insertLoadFunction(&map, GL_RG16F, GL_FLOAT, Load32FTo16F<2> ); + insertLoadFunction(&map, GL_RG8UI, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 2> ); + insertLoadFunction(&map, GL_RG8I, GL_BYTE, LoadToNative<GLbyte, 2> ); + insertLoadFunction(&map, GL_RG16UI, GL_UNSIGNED_SHORT, LoadToNative<GLushort, 2> ); + insertLoadFunction(&map, GL_RG16I, GL_SHORT, LoadToNative<GLshort, 2> ); + insertLoadFunction(&map, GL_RG32UI, GL_UNSIGNED_INT, LoadToNative<GLuint, 2> ); + insertLoadFunction(&map, GL_RG32I, GL_INT, LoadToNative<GLint, 2> ); + insertLoadFunction(&map, GL_R8, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 1> ); + insertLoadFunction(&map, GL_R8_SNORM, GL_BYTE, LoadToNative<GLbyte, 1> ); + insertLoadFunction(&map, GL_R16F, GL_HALF_FLOAT, LoadToNative<GLhalf, 1> ); + insertLoadFunction(&map, GL_R16F, GL_HALF_FLOAT_OES, LoadToNative<GLhalf, 1> ); + insertLoadFunction(&map, GL_R32F, GL_FLOAT, LoadToNative<GLfloat, 1> ); + insertLoadFunction(&map, GL_R16F, GL_FLOAT, Load32FTo16F<1> ); + insertLoadFunction(&map, GL_R8UI, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 1> ); + insertLoadFunction(&map, GL_R8I, GL_BYTE, LoadToNative<GLbyte, 1> ); + insertLoadFunction(&map, GL_R16UI, GL_UNSIGNED_SHORT, LoadToNative<GLushort, 1> ); + insertLoadFunction(&map, GL_R16I, GL_SHORT, LoadToNative<GLshort, 1> ); + insertLoadFunction(&map, GL_R32UI, GL_UNSIGNED_INT, LoadToNative<GLuint, 1> ); + insertLoadFunction(&map, GL_R32I, GL_INT, LoadToNative<GLint, 1> ); + insertLoadFunction(&map, GL_DEPTH_COMPONENT16, GL_UNSIGNED_SHORT, LoadToNative<GLushort, 1> ); + insertLoadFunction(&map, GL_DEPTH_COMPONENT24, GL_UNSIGNED_INT, LoadR32ToR24G8 ); + insertLoadFunction(&map, GL_DEPTH_COMPONENT16, GL_UNSIGNED_INT, LoadR32ToR16 ); + insertLoadFunction(&map, GL_DEPTH_COMPONENT32F, GL_FLOAT, LoadToNative<GLfloat, 1> ); + insertLoadFunction(&map, GL_DEPTH24_STENCIL8, GL_UNSIGNED_INT_24_8, LoadR32ToR24G8 ); + insertLoadFunction(&map, GL_DEPTH32F_STENCIL8, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, LoadToNative<GLuint, 2> ); + + // Unsized formats + // Load functions are unreachable because they are converted to sized internal formats based on + // the format and type before loading takes place. + insertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + insertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, UnreachableLoadFunction ); + insertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, UnreachableLoadFunction ); + insertLoadFunction(&map, GL_RGB, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + insertLoadFunction(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, UnreachableLoadFunction ); + insertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + insertLoadFunction(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + insertLoadFunction(&map, GL_ALPHA, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + + // From GL_OES_texture_float + insertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, LoadLA32FToRGBA32F ); + insertLoadFunction(&map, GL_LUMINANCE, GL_FLOAT, LoadL32FToRGBA32F ); + insertLoadFunction(&map, GL_ALPHA, GL_FLOAT, LoadA32FToRGBA32F ); + + // From GL_OES_texture_half_float + insertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, LoadLA16FToRGBA16F ); + insertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, LoadLA16FToRGBA16F ); + insertLoadFunction(&map, GL_LUMINANCE, GL_HALF_FLOAT, LoadL16FToRGBA16F ); + insertLoadFunction(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, LoadL16FToRGBA16F ); + insertLoadFunction(&map, GL_ALPHA, GL_HALF_FLOAT, LoadA16FToRGBA16F ); + insertLoadFunction(&map, GL_ALPHA, GL_HALF_FLOAT_OES, LoadA16FToRGBA16F ); + + // From GL_EXT_texture_storage + insertLoadFunction(&map, GL_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadA8ToBGRA8 ); + insertLoadFunction(&map, GL_LUMINANCE8_EXT, GL_UNSIGNED_BYTE, LoadL8ToRGBA8 ); + insertLoadFunction(&map, GL_LUMINANCE8_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadLA8ToRGBA8 ); + insertLoadFunction(&map, GL_ALPHA32F_EXT, GL_FLOAT, LoadA32FToRGBA32F ); + insertLoadFunction(&map, GL_LUMINANCE32F_EXT, GL_FLOAT, LoadL32FToRGBA32F ); + insertLoadFunction(&map, GL_LUMINANCE_ALPHA32F_EXT, GL_FLOAT, LoadLA32FToRGBA32F ); + insertLoadFunction(&map, GL_ALPHA16F_EXT, GL_HALF_FLOAT, LoadA16FToRGBA16F ); + insertLoadFunction(&map, GL_ALPHA16F_EXT, GL_HALF_FLOAT_OES, LoadA16FToRGBA16F ); + insertLoadFunction(&map, GL_LUMINANCE16F_EXT, GL_HALF_FLOAT, LoadL16FToRGBA16F ); + insertLoadFunction(&map, GL_LUMINANCE16F_EXT, GL_HALF_FLOAT_OES, LoadL16FToRGBA16F ); + insertLoadFunction(&map, GL_LUMINANCE_ALPHA16F_EXT, GL_HALF_FLOAT, LoadLA16FToRGBA16F ); + insertLoadFunction(&map, GL_LUMINANCE_ALPHA16F_EXT, GL_HALF_FLOAT_OES, LoadLA16FToRGBA16F ); + + // From GL_ANGLE_depth_texture + insertLoadFunction(&map, GL_DEPTH_COMPONENT32_OES, GL_UNSIGNED_INT, LoadR32ToR24G8 ); + + // From GL_EXT_texture_format_BGRA8888 + insertLoadFunction(&map, GL_BGRA8_EXT, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> ); + insertLoadFunction(&map, GL_BGRA4_ANGLEX, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, LoadRGBA4ToRGBA8 ); + insertLoadFunction(&map, GL_BGRA4_ANGLEX, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> ); + insertLoadFunction(&map, GL_BGR5_A1_ANGLEX, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, LoadRGB5A1ToRGBA8 ); + insertLoadFunction(&map, GL_BGR5_A1_ANGLEX, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> ); + + // Compressed formats + // From ES 3.0.1 spec, table 3.16 + // | Internal format | Type | Load function | + insertLoadFunction(&map, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + + // From GL_EXT_texture_compression_dxt1 + insertLoadFunction(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 8>); + insertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 8>); + + // From GL_ANGLE_texture_compression_dxt3 + insertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 16>); + + // From GL_ANGLE_texture_compression_dxt5 + insertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 16>); + + return map; +} + +// A map to determine the pixel size and mipmap generation function of a given DXGI format +struct DXGIFormatInfo +{ + GLuint mPixelBits; + GLuint mBlockWidth; + GLuint mBlockHeight; + GLenum mComponentType; + + MipGenerationFunction mMipGenerationFunction; + ColorReadFunction mColorReadFunction; + + DXGIFormatInfo() + : mPixelBits(0), mBlockWidth(0), mBlockHeight(0), mComponentType(GL_NONE), mMipGenerationFunction(NULL), + mColorReadFunction(NULL) + { } + + DXGIFormatInfo(GLuint pixelBits, GLuint blockWidth, GLuint blockHeight, GLenum componentType, + MipGenerationFunction mipFunc, ColorReadFunction readFunc) + : mPixelBits(pixelBits), mBlockWidth(blockWidth), mBlockHeight(blockHeight), mComponentType(componentType), + mMipGenerationFunction(mipFunc), mColorReadFunction(readFunc) + { } +}; + +typedef std::map<DXGI_FORMAT, DXGIFormatInfo> DXGIFormatInfoMap; + +void AddDXGIFormat(DXGIFormatInfoMap *map, DXGI_FORMAT dxgiFormat, GLuint pixelBits, GLuint blockWidth, GLuint blockHeight, + GLenum componentType, MipGenerationFunction mipFunc, ColorReadFunction readFunc) +{ + map->insert(std::make_pair(dxgiFormat, DXGIFormatInfo(pixelBits, blockWidth, blockHeight, componentType, mipFunc, readFunc))); +} + +static DXGIFormatInfoMap BuildDXGIFormatInfoMap() +{ + DXGIFormatInfoMap map; + + // | DXGI format |S |W |H |Component Type | Mip generation function | Color read function + AddDXGIFormat(&map, DXGI_FORMAT_UNKNOWN, 0, 0, 0, GL_NONE, NULL, NULL); + + AddDXGIFormat(&map, DXGI_FORMAT_A8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<A8>, ReadColor<A8, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R8>, ReadColor<R8, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R8G8>, ReadColor<R8G8, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R8G8B8A8>, ReadColor<R8G8B8A8, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R8G8B8A8>, ReadColor<R8G8B8A8, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_B8G8R8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<B8G8R8A8>, ReadColor<B8G8R8A8, GLfloat>); + + AddDXGIFormat(&map, DXGI_FORMAT_R8_SNORM, 8, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip<R8S>, ReadColor<R8S, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip<R8G8S>, ReadColor<R8G8S, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip<R8G8B8A8S>, ReadColor<R8G8B8A8S, GLfloat>); + + AddDXGIFormat(&map, DXGI_FORMAT_R8_UINT, 8, 1, 1, GL_UNSIGNED_INT, GenerateMip<R8>, ReadColor<R8, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R16_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip<R16>, ReadColor<R16, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R32_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip<R32>, ReadColor<R32, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip<R8G8>, ReadColor<R8G8, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip<R16G16>, ReadColor<R16G16, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip<R32G32>, ReadColor<R32G32, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_UINT, 96, 1, 1, GL_UNSIGNED_INT, GenerateMip<R32G32B32>, ReadColor<R32G32B32, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip<R8G8B8A8>, ReadColor<R8G8B8A8, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip<R16G16B16A16>, ReadColor<R16G16B16A16, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_UINT, 128, 1, 1, GL_UNSIGNED_INT, GenerateMip<R32G32B32A32>, ReadColor<R32G32B32A32, GLuint>); + + AddDXGIFormat(&map, DXGI_FORMAT_R8_SINT, 8, 1, 1, GL_INT, GenerateMip<R8S>, ReadColor<R8S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R16_SINT, 16, 1, 1, GL_INT, GenerateMip<R16S>, ReadColor<R16S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R32_SINT, 32, 1, 1, GL_INT, GenerateMip<R32S>, ReadColor<R32S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SINT, 16, 1, 1, GL_INT, GenerateMip<R8G8S>, ReadColor<R8G8S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SINT, 32, 1, 1, GL_INT, GenerateMip<R16G16S>, ReadColor<R16G16S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32_SINT, 64, 1, 1, GL_INT, GenerateMip<R32G32S>, ReadColor<R32G32S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_SINT, 96, 1, 1, GL_INT, GenerateMip<R32G32B32S>, ReadColor<R32G32B32S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SINT, 32, 1, 1, GL_INT, GenerateMip<R8G8B8A8S>, ReadColor<R8G8B8A8S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SINT, 64, 1, 1, GL_INT, GenerateMip<R16G16B16A16S>, ReadColor<R16G16B16A16S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_SINT, 128, 1, 1, GL_INT, GenerateMip<R32G32B32A32S>, ReadColor<R32G32B32A32S, GLint>); + + AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R10G10B10A2>, ReadColor<R10G10B10A2, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip<R10G10B10A2>, ReadColor<R10G10B10A2, GLuint>); + + AddDXGIFormat(&map, DXGI_FORMAT_R16_FLOAT, 16, 1, 1, GL_FLOAT, GenerateMip<R16F>, ReadColor<R16F, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip<R16G16F>, ReadColor<R16G16F, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip<R16G16B16A16F>, ReadColor<R16G16B16A16F, GLfloat>); + + AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip<R32F>, ReadColor<R32F, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip<R32G32F>, ReadColor<R32G32F, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_FLOAT, 96, 1, 1, GL_FLOAT, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, 128, 1, 1, GL_FLOAT, GenerateMip<R32G32B32A32F>, ReadColor<R32G32B32A32F, GLfloat>); + + AddDXGIFormat(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 32, 1, 1, GL_FLOAT, GenerateMip<R9G9B9E5>, ReadColor<R9G9B9E5, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R11G11B10_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip<R11G11B10F>, ReadColor<R11G11B10F, GLfloat>); + + AddDXGIFormat(&map, DXGI_FORMAT_R16_TYPELESS, 16, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_D16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R24G8_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, 32, 1, 1, GL_UNSIGNED_INT, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R32G8X24_TYPELESS, 64, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, 64, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, 64, 1, 1, GL_UNSIGNED_INT, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R32_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_D32_FLOAT, 32, 1, 1, GL_FLOAT, NULL, NULL); + + AddDXGIFormat(&map, DXGI_FORMAT_BC1_UNORM, 64, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_BC2_UNORM, 128, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_BC3_UNORM, 128, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL); + + // Useful formats for vertex buffers + AddDXGIFormat(&map, DXGI_FORMAT_R16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UNORM, 64, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SNORM, 64, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL); + + return map; +} + +typedef std::map<DXGI_FORMAT, GLenum> DXGIToESFormatMap; + +inline void AddDXGIToESEntry(DXGIToESFormatMap *map, DXGI_FORMAT key, GLenum value) +{ + map->insert(std::make_pair(key, value)); +} + +static DXGIToESFormatMap BuildDXGIToESFormatMap() +{ + DXGIToESFormatMap map; + + AddDXGIToESEntry(&map, DXGI_FORMAT_UNKNOWN, GL_NONE); + + AddDXGIToESEntry(&map, DXGI_FORMAT_A8_UNORM, GL_ALPHA8_EXT); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8_UNORM, GL_R8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_UNORM, GL_RG8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UNORM, GL_RGBA8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, GL_SRGB8_ALPHA8); + AddDXGIToESEntry(&map, DXGI_FORMAT_B8G8R8A8_UNORM, GL_BGRA8_EXT); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R8_SNORM, GL_R8_SNORM); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_SNORM, GL_RG8_SNORM); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_SNORM, GL_RGBA8_SNORM); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R8_UINT, GL_R8UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_UINT, GL_R16UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_UINT, GL_R32UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_UINT, GL_RG8UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_UINT, GL_RG16UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_UINT, GL_RG32UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_UINT, GL_RGB32UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UINT, GL_RGBA8UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_UINT, GL_RGBA16UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_UINT, GL_RGBA32UI); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R8_SINT, GL_R8I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_SINT, GL_R16I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_SINT, GL_R32I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_SINT, GL_RG8I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_SINT, GL_RG16I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_SINT, GL_RG32I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_SINT, GL_RGB32I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_SINT, GL_RGBA8I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_SINT, GL_RGBA16I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_SINT, GL_RGBA32I); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R10G10B10A2_UNORM, GL_RGB10_A2); + AddDXGIToESEntry(&map, DXGI_FORMAT_R10G10B10A2_UINT, GL_RGB10_A2UI); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_FLOAT, GL_R16F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_FLOAT, GL_RG16F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, GL_RGBA16F); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_FLOAT, GL_R32F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_FLOAT, GL_RG32F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_FLOAT, GL_RGB32F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, GL_RGBA32F); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, GL_RGB9_E5); + AddDXGIToESEntry(&map, DXGI_FORMAT_R11G11B10_FLOAT, GL_R11F_G11F_B10F); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_TYPELESS, GL_DEPTH_COMPONENT16); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_UNORM, GL_DEPTH_COMPONENT16); + AddDXGIToESEntry(&map, DXGI_FORMAT_D16_UNORM, GL_DEPTH_COMPONENT16); + AddDXGIToESEntry(&map, DXGI_FORMAT_R24G8_TYPELESS, GL_DEPTH24_STENCIL8_OES); + AddDXGIToESEntry(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, GL_DEPTH24_STENCIL8_OES); + AddDXGIToESEntry(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, GL_DEPTH24_STENCIL8_OES); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G8X24_TYPELESS, GL_DEPTH32F_STENCIL8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, GL_DEPTH32F_STENCIL8); + AddDXGIToESEntry(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, GL_DEPTH32F_STENCIL8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_TYPELESS, GL_DEPTH_COMPONENT32F); + AddDXGIToESEntry(&map, DXGI_FORMAT_D32_FLOAT, GL_DEPTH_COMPONENT32F); + + AddDXGIToESEntry(&map, DXGI_FORMAT_BC1_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); + AddDXGIToESEntry(&map, DXGI_FORMAT_BC2_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE); + AddDXGIToESEntry(&map, DXGI_FORMAT_BC3_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE); + + return map; +} + +static const DXGIToESFormatMap &GetDXGIToESFormatMap() +{ + static const DXGIToESFormatMap map = BuildDXGIToESFormatMap(); + return map; +} + +static const DXGIFormatInfoMap &GetDXGIFormatInfoMap() +{ + static const DXGIFormatInfoMap infoMap = BuildDXGIFormatInfoMap(); + return infoMap; +} + +static bool GetDXGIFormatInfo(DXGI_FORMAT format, DXGIFormatInfo *outFormatInfo) +{ + const DXGIFormatInfoMap &infoMap = GetDXGIFormatInfoMap(); + DXGIFormatInfoMap::const_iterator iter = infoMap.find(format); + if (iter != infoMap.end()) + { + if (outFormatInfo) + { + *outFormatInfo = iter->second; + } + return true; + } + else + { + return false; + } +} + +static d3d11::DXGIFormatSet BuildAllDXGIFormatSet() +{ + d3d11::DXGIFormatSet set; + + const DXGIFormatInfoMap &infoMap = GetDXGIFormatInfoMap(); + for (DXGIFormatInfoMap::const_iterator i = infoMap.begin(); i != infoMap.end(); ++i) + { + set.insert(i->first); + } + + return set; +} + +struct D3D11FastCopyFormat +{ + DXGI_FORMAT mSourceFormat; + GLenum mDestFormat; + GLenum mDestType; + + D3D11FastCopyFormat(DXGI_FORMAT sourceFormat, GLenum destFormat, GLenum destType) + : mSourceFormat(sourceFormat), mDestFormat(destFormat), mDestType(destType) + { } + + bool operator<(const D3D11FastCopyFormat& other) const + { + return memcmp(this, &other, sizeof(D3D11FastCopyFormat)) < 0; + } +}; + +typedef std::map<D3D11FastCopyFormat, ColorCopyFunction> D3D11FastCopyMap; +typedef std::pair<D3D11FastCopyFormat, ColorCopyFunction> D3D11FastCopyPair; + +static D3D11FastCopyMap BuildFastCopyMap() +{ + D3D11FastCopyMap map; + + map.insert(D3D11FastCopyPair(D3D11FastCopyFormat(DXGI_FORMAT_B8G8R8A8_UNORM, GL_RGBA, GL_UNSIGNED_BYTE), CopyBGRAUByteToRGBAUByte)); + + return map; +} + +struct DXGIDepthStencilInfo +{ + unsigned int mDepthBits; + unsigned int mDepthOffset; + unsigned int mStencilBits; + unsigned int mStencilOffset; + + DXGIDepthStencilInfo() + : mDepthBits(0), mDepthOffset(0), mStencilBits(0), mStencilOffset(0) + { } + + DXGIDepthStencilInfo(unsigned int depthBits, unsigned int depthOffset, unsigned int stencilBits, unsigned int stencilOffset) + : mDepthBits(depthBits), mDepthOffset(depthOffset), mStencilBits(stencilBits), mStencilOffset(stencilOffset) + { } +}; + +typedef std::map<DXGI_FORMAT, DXGIDepthStencilInfo> DepthStencilInfoMap; +typedef std::pair<DXGI_FORMAT, DXGIDepthStencilInfo> DepthStencilInfoPair; + +static DepthStencilInfoMap BuildDepthStencilInfoMap() +{ + DepthStencilInfoMap map; + + map.insert(DepthStencilInfoPair(DXGI_FORMAT_R16_TYPELESS, DXGIDepthStencilInfo(16, 0, 0, 0))); + map.insert(DepthStencilInfoPair(DXGI_FORMAT_R16_UNORM, DXGIDepthStencilInfo(16, 0, 0, 0))); + map.insert(DepthStencilInfoPair(DXGI_FORMAT_D16_UNORM, DXGIDepthStencilInfo(16, 0, 0, 0))); + + map.insert(DepthStencilInfoPair(DXGI_FORMAT_R24G8_TYPELESS, DXGIDepthStencilInfo(24, 0, 8, 24))); + map.insert(DepthStencilInfoPair(DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGIDepthStencilInfo(24, 0, 8, 24))); + map.insert(DepthStencilInfoPair(DXGI_FORMAT_D24_UNORM_S8_UINT, DXGIDepthStencilInfo(24, 0, 8, 24))); + + map.insert(DepthStencilInfoPair(DXGI_FORMAT_R32_TYPELESS, DXGIDepthStencilInfo(32, 0, 0, 0))); + map.insert(DepthStencilInfoPair(DXGI_FORMAT_R32_FLOAT, DXGIDepthStencilInfo(32, 0, 0, 0))); + map.insert(DepthStencilInfoPair(DXGI_FORMAT_D32_FLOAT, DXGIDepthStencilInfo(32, 0, 0, 0))); + + map.insert(DepthStencilInfoPair(DXGI_FORMAT_R32G8X24_TYPELESS, DXGIDepthStencilInfo(32, 0, 8, 32))); + map.insert(DepthStencilInfoPair(DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, DXGIDepthStencilInfo(32, 0, 8, 32))); + map.insert(DepthStencilInfoPair(DXGI_FORMAT_D32_FLOAT_S8X24_UINT, DXGIDepthStencilInfo(32, 0, 8, 32))); + + return map; +} + +static const DepthStencilInfoMap &GetDepthStencilInfoMap() +{ + static const DepthStencilInfoMap infoMap = BuildDepthStencilInfoMap(); + return infoMap; +} + +bool GetDepthStencilInfo(DXGI_FORMAT format, DXGIDepthStencilInfo *outDepthStencilInfo) +{ + const DepthStencilInfoMap& infoMap = GetDepthStencilInfoMap(); + DepthStencilInfoMap::const_iterator iter = infoMap.find(format); + if (iter != infoMap.end()) + { + if (outDepthStencilInfo) + { + *outDepthStencilInfo = iter->second; + } + return true; + } + else + { + return false; + } +} + +struct SwizzleSizeType +{ + unsigned int mMaxComponentSize; + GLenum mComponentType; + + SwizzleSizeType() + : mMaxComponentSize(0), mComponentType(GL_NONE) + { } + + SwizzleSizeType(unsigned int maxComponentSize, GLenum componentType) + : mMaxComponentSize(maxComponentSize), mComponentType(componentType) + { } + + bool operator<(const SwizzleSizeType& other) const + { + return (mMaxComponentSize != other.mMaxComponentSize) ? (mMaxComponentSize < other.mMaxComponentSize) + : (mComponentType < other.mComponentType); + } +}; + +struct SwizzleFormatInfo +{ + DXGI_FORMAT mTexFormat; + DXGI_FORMAT mSRVFormat; + DXGI_FORMAT mRTVFormat; + + SwizzleFormatInfo() + : mTexFormat(DXGI_FORMAT_UNKNOWN), mSRVFormat(DXGI_FORMAT_UNKNOWN), mRTVFormat(DXGI_FORMAT_UNKNOWN) + { } + + SwizzleFormatInfo(DXGI_FORMAT texFormat, DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat) + : mTexFormat(texFormat), mSRVFormat(srvFormat), mRTVFormat(rtvFormat) + { } +}; + +typedef std::map<SwizzleSizeType, SwizzleFormatInfo> SwizzleInfoMap; +typedef std::pair<SwizzleSizeType, SwizzleFormatInfo> SwizzleInfoPair; + +static SwizzleInfoMap BuildSwizzleInfoMap() +{ + SwizzleInfoMap map; + + map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM))); + map.insert(SwizzleInfoPair(SwizzleSizeType(24, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT))); + map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT))); + + map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_SIGNED_NORMALIZED ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM ))); + + map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_FLOAT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT))); + map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_FLOAT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT))); + + map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT ))); + + map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT ))); + + return map; +} +typedef std::pair<GLint, InitializeTextureDataFunction> InternalFormatInitializerPair; +typedef std::map<GLint, InitializeTextureDataFunction> InternalFormatInitializerMap; + +static InternalFormatInitializerMap BuildInternalFormatInitializerMap() +{ + InternalFormatInitializerMap map; + + map.insert(InternalFormatInitializerPair(GL_RGB8, Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF> )); + map.insert(InternalFormatInitializerPair(GL_RGB565, Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF> )); + map.insert(InternalFormatInitializerPair(GL_SRGB8, Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF> )); + map.insert(InternalFormatInitializerPair(GL_RGB16F, Initialize4ComponentData<GLhalf, 0x0000, 0x0000, 0x0000, gl::Float16One>)); + map.insert(InternalFormatInitializerPair(GL_RGB32F, Initialize4ComponentData<GLfloat, 0x00000000, 0x00000000, 0x00000000, gl::Float32One>)); + map.insert(InternalFormatInitializerPair(GL_RGB8UI, Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0x01> )); + map.insert(InternalFormatInitializerPair(GL_RGB8I, Initialize4ComponentData<GLbyte, 0x00, 0x00, 0x00, 0x01> )); + map.insert(InternalFormatInitializerPair(GL_RGB16UI, Initialize4ComponentData<GLushort, 0x0000, 0x0000, 0x0000, 0x0001> )); + map.insert(InternalFormatInitializerPair(GL_RGB16I, Initialize4ComponentData<GLshort, 0x0000, 0x0000, 0x0000, 0x0001> )); + map.insert(InternalFormatInitializerPair(GL_RGB32UI, Initialize4ComponentData<GLuint, 0x00000000, 0x00000000, 0x00000000, 0x00000001> )); + map.insert(InternalFormatInitializerPair(GL_RGB32I, Initialize4ComponentData<GLint, 0x00000000, 0x00000000, 0x00000000, 0x00000001> )); + + return map; +} + +static const SwizzleInfoMap &GetSwizzleInfoMap() +{ + static const SwizzleInfoMap map = BuildSwizzleInfoMap(); + return map; +} + +static const SwizzleFormatInfo GetSwizzleFormatInfo(GLenum internalFormat) +{ + // Get the maximum sized component + unsigned int maxBits = 1; + + if (gl::IsFormatCompressed(internalFormat)) + { + unsigned int compressedBitsPerBlock = gl::GetPixelBytes(internalFormat) * 8; + unsigned int blockSize = gl::GetCompressedBlockWidth(internalFormat) * + gl::GetCompressedBlockHeight(internalFormat); + maxBits = std::max(compressedBitsPerBlock / blockSize, maxBits); + } + else + { + maxBits = std::max(maxBits, gl::GetAlphaBits( internalFormat)); + maxBits = std::max(maxBits, gl::GetRedBits( internalFormat)); + maxBits = std::max(maxBits, gl::GetGreenBits( internalFormat)); + maxBits = std::max(maxBits, gl::GetBlueBits( internalFormat)); + maxBits = std::max(maxBits, gl::GetLuminanceBits(internalFormat)); + maxBits = std::max(maxBits, gl::GetDepthBits( internalFormat)); + } + + maxBits = roundUp(maxBits, 8U); + + GLenum componentType = gl::GetComponentType(internalFormat); + + const SwizzleInfoMap &map = GetSwizzleInfoMap(); + SwizzleInfoMap::const_iterator iter = map.find(SwizzleSizeType(maxBits, componentType)); + + if (iter != map.end()) + { + return iter->second; + } + else + { + UNREACHABLE(); + static const SwizzleFormatInfo defaultFormatInfo; + return defaultFormatInfo; + } +} + +static const InternalFormatInitializerMap &GetInternalFormatInitializerMap() +{ + static const InternalFormatInitializerMap map = BuildInternalFormatInitializerMap(); + return map; +} + +namespace d3d11 +{ + +MipGenerationFunction GetMipGenerationFunction(DXGI_FORMAT format) +{ + DXGIFormatInfo formatInfo; + if (GetDXGIFormatInfo(format, &formatInfo)) + { + return formatInfo.mMipGenerationFunction; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +LoadImageFunction GetImageLoadFunction(GLenum internalFormat, GLenum type) +{ + static const D3D11LoadFunctionMap loadImageMap = buildD3D11LoadFunctionMap(); + D3D11LoadFunctionMap::const_iterator iter = loadImageMap.find(InternalFormatTypePair(internalFormat, type)); + if (iter != loadImageMap.end()) + { + return iter->second; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +GLuint GetFormatPixelBytes(DXGI_FORMAT format) +{ + DXGIFormatInfo dxgiFormatInfo; + if (GetDXGIFormatInfo(format, &dxgiFormatInfo)) + { + return dxgiFormatInfo.mPixelBits / 8; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetBlockWidth(DXGI_FORMAT format) +{ + DXGIFormatInfo dxgiFormatInfo; + if (GetDXGIFormatInfo(format, &dxgiFormatInfo)) + { + return dxgiFormatInfo.mBlockWidth; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetBlockHeight(DXGI_FORMAT format) +{ + DXGIFormatInfo dxgiFormatInfo; + if (GetDXGIFormatInfo(format, &dxgiFormatInfo)) + { + return dxgiFormatInfo.mBlockHeight; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLenum GetComponentType(DXGI_FORMAT format) +{ + DXGIFormatInfo dxgiFormatInfo; + if (GetDXGIFormatInfo(format, &dxgiFormatInfo)) + { + return dxgiFormatInfo.mComponentType; + } + else + { + UNREACHABLE(); + return GL_NONE; + } +} + +GLuint GetDepthBits(DXGI_FORMAT format) +{ + DXGIDepthStencilInfo dxgiDSInfo; + if (GetDepthStencilInfo(format, &dxgiDSInfo)) + { + return dxgiDSInfo.mDepthBits; + } + else + { + // Since the depth stencil info map does not contain all used DXGI formats, + // we should not assert that the format exists + return 0; + } +} + +GLuint GetDepthOffset(DXGI_FORMAT format) +{ + DXGIDepthStencilInfo dxgiDSInfo; + if (GetDepthStencilInfo(format, &dxgiDSInfo)) + { + return dxgiDSInfo.mDepthOffset; + } + else + { + // Since the depth stencil info map does not contain all used DXGI formats, + // we should not assert that the format exists + return 0; + } +} + +GLuint GetStencilBits(DXGI_FORMAT format) +{ + DXGIDepthStencilInfo dxgiDSInfo; + if (GetDepthStencilInfo(format, &dxgiDSInfo)) + { + return dxgiDSInfo.mStencilBits; + } + else + { + // Since the depth stencil info map does not contain all used DXGI formats, + // we should not assert that the format exists + return 0; + } +} + +GLuint GetStencilOffset(DXGI_FORMAT format) +{ + DXGIDepthStencilInfo dxgiDSInfo; + if (GetDepthStencilInfo(format, &dxgiDSInfo)) + { + return dxgiDSInfo.mStencilOffset; + } + else + { + // Since the depth stencil info map does not contain all used DXGI formats, + // we should not assert that the format exists + return 0; + } +} + +void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset) +{ + DXGIFormatInfo dxgiFormatInfo; + if (GetDXGIFormatInfo(format, &dxgiFormatInfo)) + { + int upsampleCount = 0; + + GLsizei blockWidth = dxgiFormatInfo.mBlockWidth; + GLsizei blockHeight = dxgiFormatInfo.mBlockHeight; + + // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already. + if (isImage || *requestWidth < blockWidth || *requestHeight < blockHeight) + { + while (*requestWidth % blockWidth != 0 || *requestHeight % blockHeight != 0) + { + *requestWidth <<= 1; + *requestHeight <<= 1; + upsampleCount++; + } + } + *levelOffset = upsampleCount; + } + else + { + UNREACHABLE(); + } +} + +const DXGIFormatSet &GetAllUsedDXGIFormats() +{ + static DXGIFormatSet formatSet = BuildAllDXGIFormatSet(); + return formatSet; +} + +ColorReadFunction GetColorReadFunction(DXGI_FORMAT format) +{ + DXGIFormatInfo dxgiFormatInfo; + if (GetDXGIFormatInfo(format, &dxgiFormatInfo)) + { + return dxgiFormatInfo.mColorReadFunction; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +ColorCopyFunction GetFastCopyFunction(DXGI_FORMAT sourceFormat, GLenum destFormat, GLenum destType) +{ + static const D3D11FastCopyMap fastCopyMap = BuildFastCopyMap(); + D3D11FastCopyMap::const_iterator iter = fastCopyMap.find(D3D11FastCopyFormat(sourceFormat, destFormat, destType)); + return (iter != fastCopyMap.end()) ? iter->second : NULL; +} + +} + +namespace gl_d3d11 +{ + +DXGI_FORMAT GetTexFormat(GLenum internalFormat) +{ + D3D11FormatInfo d3d11FormatInfo; + if (GetD3D11FormatInfo(internalFormat, &d3d11FormatInfo)) + { + return d3d11FormatInfo.mTexFormat; + } + else + { + UNREACHABLE(); + return DXGI_FORMAT_UNKNOWN; + } +} + +DXGI_FORMAT GetSRVFormat(GLenum internalFormat) +{ + D3D11FormatInfo d3d11FormatInfo; + if (GetD3D11FormatInfo(internalFormat, &d3d11FormatInfo)) + { + return d3d11FormatInfo.mSRVFormat; + } + else + { + UNREACHABLE(); + return DXGI_FORMAT_UNKNOWN; + } +} + +DXGI_FORMAT GetRTVFormat(GLenum internalFormat) +{ + D3D11FormatInfo d3d11FormatInfo; + if (GetD3D11FormatInfo(internalFormat, &d3d11FormatInfo)) + { + return d3d11FormatInfo.mRTVFormat; + } + else + { + UNREACHABLE(); + return DXGI_FORMAT_UNKNOWN; + } +} + +DXGI_FORMAT GetDSVFormat(GLenum internalFormat) +{ + D3D11FormatInfo d3d11FormatInfo; + if (GetD3D11FormatInfo(internalFormat, &d3d11FormatInfo)) + { + return d3d11FormatInfo.mDSVFormat; + } + else + { + return DXGI_FORMAT_UNKNOWN; + } +} + +// Given a GL internal format, this function returns the DSV format if it is depth- or stencil-renderable, +// the RTV format if it is color-renderable, and the (nonrenderable) texture format otherwise. +DXGI_FORMAT GetRenderableFormat(GLenum internalFormat) +{ + DXGI_FORMAT targetFormat = GetDSVFormat(internalFormat); + if (targetFormat == DXGI_FORMAT_UNKNOWN) + targetFormat = GetRTVFormat(internalFormat); + if (targetFormat == DXGI_FORMAT_UNKNOWN) + targetFormat = GetTexFormat(internalFormat); + + return targetFormat; +} + +DXGI_FORMAT GetSwizzleTexFormat(GLint internalFormat) +{ + if (GetRTVFormat(internalFormat) == DXGI_FORMAT_UNKNOWN || gl::GetComponentCount(internalFormat) != 4) + { + const SwizzleFormatInfo &swizzleInfo = GetSwizzleFormatInfo(internalFormat); + return swizzleInfo.mTexFormat; + } + else + { + return GetTexFormat(internalFormat); + } +} + +DXGI_FORMAT GetSwizzleSRVFormat(GLint internalFormat) +{ + if (GetRTVFormat(internalFormat) == DXGI_FORMAT_UNKNOWN || gl::GetComponentCount(internalFormat) != 4) + { + const SwizzleFormatInfo &swizzleInfo = GetSwizzleFormatInfo(internalFormat); + return swizzleInfo.mSRVFormat; + } + else + { + return GetSRVFormat(internalFormat); + } +} + +DXGI_FORMAT GetSwizzleRTVFormat(GLint internalFormat) +{ + if (GetRTVFormat(internalFormat) == DXGI_FORMAT_UNKNOWN || gl::GetComponentCount(internalFormat) != 4) + { + const SwizzleFormatInfo &swizzleInfo = GetSwizzleFormatInfo(internalFormat); + return swizzleInfo.mRTVFormat; + } + else + { + return GetRTVFormat(internalFormat); + } +} + +bool RequiresTextureDataInitialization(GLint internalFormat) +{ + const InternalFormatInitializerMap &map = GetInternalFormatInitializerMap(); + return map.find(internalFormat) != map.end(); +} + +InitializeTextureDataFunction GetTextureDataInitializationFunction(GLint internalFormat) +{ + const InternalFormatInitializerMap &map = GetInternalFormatInitializerMap(); + InternalFormatInitializerMap::const_iterator iter = map.find(internalFormat); + if (iter != map.end()) + { + return iter->second; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +struct D3D11VertexFormatInfo +{ + rx::VertexConversionType mConversionType; + DXGI_FORMAT mNativeFormat; + VertexCopyFunction mCopyFunction; + + D3D11VertexFormatInfo() + : mConversionType(VERTEX_CONVERT_NONE), + mNativeFormat(DXGI_FORMAT_UNKNOWN), + mCopyFunction(NULL) + {} + + D3D11VertexFormatInfo(VertexConversionType conversionType, DXGI_FORMAT nativeFormat, VertexCopyFunction copyFunction) + : mConversionType(conversionType), + mNativeFormat(nativeFormat), + mCopyFunction(copyFunction) + {} +}; + +typedef std::map<gl::VertexFormat, D3D11VertexFormatInfo> D3D11VertexFormatInfoMap; + +typedef std::pair<gl::VertexFormat, D3D11VertexFormatInfo> D3D11VertexFormatPair; + +static void addVertexFormatInfo(D3D11VertexFormatInfoMap *map, GLenum inputType, GLboolean normalized, GLuint componentCount, + VertexConversionType conversionType, DXGI_FORMAT nativeFormat, VertexCopyFunction copyFunction) +{ + gl::VertexFormat inputFormat(inputType, normalized, componentCount, false); + map->insert(D3D11VertexFormatPair(inputFormat, D3D11VertexFormatInfo(conversionType, nativeFormat, copyFunction))); +} + +static void addIntegerVertexFormatInfo(D3D11VertexFormatInfoMap *map, GLenum inputType, GLuint componentCount, + VertexConversionType conversionType, DXGI_FORMAT nativeFormat, VertexCopyFunction copyFunction) +{ + gl::VertexFormat inputFormat(inputType, GL_FALSE, componentCount, true); + map->insert(D3D11VertexFormatPair(inputFormat, D3D11VertexFormatInfo(conversionType, nativeFormat, copyFunction))); +} + +static D3D11VertexFormatInfoMap BuildD3D11VertexFormatInfoMap() +{ + D3D11VertexFormatInfoMap map; + + // TODO: column legend + + // + // Float formats + // + + // GL_BYTE -- un-normalized + addVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_SINT, ©VertexData<GLbyte, 1, 0>); + addVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_SINT, ©VertexData<GLbyte, 2, 0>); + addVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_SINT, ©VertexData<GLbyte, 3, 1>); + addVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_SINT, ©VertexData<GLbyte, 4, 0>); + + // GL_BYTE -- normalized + addVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SNORM, ©VertexData<GLbyte, 1, 0>); + addVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SNORM, ©VertexData<GLbyte, 2, 0>); + addVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SNORM, ©VertexData<GLbyte, 3, INT8_MAX>); + addVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SNORM, ©VertexData<GLbyte, 4, 0>); + + // GL_UNSIGNED_BYTE -- un-normalized + addVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_UINT, ©VertexData<GLubyte, 1, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_UINT, ©VertexData<GLubyte, 2, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, ©VertexData<GLubyte, 3, 1>); + addVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_UINT, ©VertexData<GLubyte, 4, 0>); + + // GL_UNSIGNED_BYTE -- normalized + addVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UNORM, ©VertexData<GLubyte, 1, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UNORM, ©VertexData<GLubyte, 2, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, ©VertexData<GLubyte, 3, UINT8_MAX>); + addVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UNORM, ©VertexData<GLubyte, 4, 0>); + + // GL_SHORT -- un-normalized + addVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_SINT, ©VertexData<GLshort, 1, 0>); + addVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_SINT, ©VertexData<GLshort, 2, 0>); + addVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, ©VertexData<GLshort, 4, 1>); + addVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_SINT, ©VertexData<GLshort, 4, 0>); + + // GL_SHORT -- normalized + addVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SNORM, ©VertexData<GLshort, 1, 0>); + addVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SNORM, ©VertexData<GLshort, 2, 0>); + addVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, ©VertexData<GLshort, 3, INT16_MAX>); + addVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SNORM, ©VertexData<GLshort, 4, 0>); + + // GL_UNSIGNED_SHORT -- un-normalized + addVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_UINT, ©VertexData<GLushort, 1, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_UINT, ©VertexData<GLushort, 2, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_UINT, ©VertexData<GLushort, 3, 1>); + addVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_UINT, ©VertexData<GLushort, 4, 0>); + + // GL_UNSIGNED_SHORT -- normalized + addVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UNORM, ©VertexData<GLushort, 1, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UNORM, ©VertexData<GLushort, 2, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UNORM, ©VertexData<GLushort, 3, UINT16_MAX>); + addVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UNORM, ©VertexData<GLushort, 4, 0>); + + // GL_INT -- un-normalized + addVertexFormatInfo(&map, GL_INT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_SINT, ©VertexData<GLint, 1, 0>); + addVertexFormatInfo(&map, GL_INT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_SINT, ©VertexData<GLint, 2, 0>); + addVertexFormatInfo(&map, GL_INT, GL_FALSE, 3, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_SINT, ©VertexData<GLint, 3, 0>); + addVertexFormatInfo(&map, GL_INT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_SINT, ©VertexData<GLint, 4, 0>); + + // GL_INT -- normalized + addVertexFormatInfo(&map, GL_INT, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, ©ToFloatVertexData<GLint, 1, true>); + addVertexFormatInfo(&map, GL_INT, GL_TRUE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, ©ToFloatVertexData<GLint, 2, true>); + addVertexFormatInfo(&map, GL_INT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, ©ToFloatVertexData<GLint, 3, true>); + addVertexFormatInfo(&map, GL_INT, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, ©ToFloatVertexData<GLint, 4, true>); + + // GL_UNSIGNED_INT -- un-normalized + addVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_UINT, ©VertexData<GLuint, 1, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_UINT, ©VertexData<GLuint, 2, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 3, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_UINT, ©VertexData<GLuint, 3, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_UINT, ©VertexData<GLuint, 4, 0>); + + // GL_UNSIGNED_INT -- normalized + addVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, ©ToFloatVertexData<GLuint, 1, true>); + addVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, ©ToFloatVertexData<GLuint, 2, true>); + addVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, ©ToFloatVertexData<GLuint, 3, true>); + addVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, ©ToFloatVertexData<GLuint, 4, true>); + + // GL_FIXED + addVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, ©FixedVertexData<1>); + addVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, ©FixedVertexData<2>); + addVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, ©FixedVertexData<3>); + addVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, ©FixedVertexData<4>); + + // GL_HALF_FLOAT + addVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_FLOAT, ©VertexData<GLhalf, 1, 0>); + addVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_FLOAT, ©VertexData<GLhalf, 2, 0>); + addVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_FLOAT, ©VertexData<GLhalf, 3, gl::Float16One>); + addVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_FLOAT, ©VertexData<GLhalf, 4, 0>); + + // GL_FLOAT + addVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, ©VertexData<GLfloat, 1, 0>); + addVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, ©VertexData<GLfloat, 2, 0>); + addVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_FLOAT, ©VertexData<GLfloat, 3, 0>); + addVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, ©VertexData<GLfloat, 4, 0>); + + // GL_INT_2_10_10_10_REV + addVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, ©PackedVertexData<true, false, true>); + addVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, ©PackedVertexData<true, true, true>); + + // GL_UNSIGNED_INT_2_10_10_10_REV + addVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, ©PackedVertexData<false, false, true>); + addVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UNORM, ©PackedUnsignedVertexData); + + // + // Integer Formats + // + + // GL_BYTE + addIntegerVertexFormatInfo(&map, GL_BYTE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SINT, ©VertexData<GLbyte, 1, 0>); + addIntegerVertexFormatInfo(&map, GL_BYTE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SINT, ©VertexData<GLbyte, 2, 0>); + addIntegerVertexFormatInfo(&map, GL_BYTE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SINT, ©VertexData<GLbyte, 3, 1>); + addIntegerVertexFormatInfo(&map, GL_BYTE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SINT, ©VertexData<GLbyte, 4, 0>); + + // GL_UNSIGNED_BYTE + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UINT, ©VertexData<GLubyte, 1, 0>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UINT, ©VertexData<GLubyte, 2, 0>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UINT, ©VertexData<GLubyte, 3, 1>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UINT, ©VertexData<GLubyte, 4, 0>); + + // GL_SHORT + addIntegerVertexFormatInfo(&map, GL_SHORT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SINT, ©VertexData<GLshort, 1, 0>); + addIntegerVertexFormatInfo(&map, GL_SHORT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SINT, ©VertexData<GLshort, 2, 0>); + addIntegerVertexFormatInfo(&map, GL_SHORT, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, ©VertexData<GLshort, 3, 1>); + addIntegerVertexFormatInfo(&map, GL_SHORT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SINT, ©VertexData<GLshort, 4, 0>); + + // GL_UNSIGNED_SHORT + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UINT, ©VertexData<GLushort, 1, 0>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UINT, ©VertexData<GLushort, 2, 0>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UINT, ©VertexData<GLushort, 3, 1>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UINT, ©VertexData<GLushort, 4, 0>); + + // GL_INT + addIntegerVertexFormatInfo(&map, GL_INT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, ©VertexData<GLint, 1, 0>); + addIntegerVertexFormatInfo(&map, GL_INT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, ©VertexData<GLint, 2, 0>); + addIntegerVertexFormatInfo(&map, GL_INT, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, ©VertexData<GLint, 3, 0>); + addIntegerVertexFormatInfo(&map, GL_INT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, ©VertexData<GLint, 4, 0>); + + // GL_UNSIGNED_INT + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, ©VertexData<GLuint, 1, 0>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, ©VertexData<GLuint, 2, 0>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, ©VertexData<GLuint, 3, 0>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, ©VertexData<GLuint, 4, 0>); + + // GL_INT_2_10_10_10_REV + addIntegerVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, ©PackedVertexData<true, true, false>); + + // GL_UNSIGNED_INT_2_10_10_10_REV + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UINT, ©PackedUnsignedVertexData); + + return map; +} + +static bool GetD3D11VertexFormatInfo(const gl::VertexFormat &vertexFormat, D3D11VertexFormatInfo *outVertexFormatInfo) +{ + static const D3D11VertexFormatInfoMap vertexFormatMap = BuildD3D11VertexFormatInfoMap(); + + D3D11VertexFormatInfoMap::const_iterator iter = vertexFormatMap.find(vertexFormat); + if (iter != vertexFormatMap.end()) + { + if (outVertexFormatInfo) + { + *outVertexFormatInfo = iter->second; + } + return true; + } + else + { + return false; + } +} + +VertexCopyFunction GetVertexCopyFunction(const gl::VertexFormat &vertexFormat) +{ + D3D11VertexFormatInfo vertexFormatInfo; + if (GetD3D11VertexFormatInfo(vertexFormat, &vertexFormatInfo)) + { + return vertexFormatInfo.mCopyFunction; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +size_t GetVertexElementSize(const gl::VertexFormat &vertexFormat) +{ + D3D11VertexFormatInfo vertexFormatInfo; + if (GetD3D11VertexFormatInfo(vertexFormat, &vertexFormatInfo)) + { + // FIXME: should not need a client version, and is not a pixel! + return d3d11::GetFormatPixelBytes(vertexFormatInfo.mNativeFormat); + } + else + { + UNREACHABLE(); + return 0; + } +} + +rx::VertexConversionType GetVertexConversionType(const gl::VertexFormat &vertexFormat) +{ + D3D11VertexFormatInfo vertexFormatInfo; + if (GetD3D11VertexFormatInfo(vertexFormat, &vertexFormatInfo)) + { + return vertexFormatInfo.mConversionType; + } + else + { + UNREACHABLE(); + return VERTEX_CONVERT_NONE; + } +} + +DXGI_FORMAT GetNativeVertexFormat(const gl::VertexFormat &vertexFormat) +{ + D3D11VertexFormatInfo vertexFormatInfo; + if (GetD3D11VertexFormatInfo(vertexFormat, &vertexFormatInfo)) + { + return vertexFormatInfo.mNativeFormat; + } + else + { + UNREACHABLE(); + return DXGI_FORMAT_UNKNOWN; + } +} + +} + +namespace d3d11_gl +{ + +GLenum GetInternalFormat(DXGI_FORMAT format) +{ + const DXGIToESFormatMap &formatMap = GetDXGIToESFormatMap(); + DXGIToESFormatMap::const_iterator iter = formatMap.find(format); + if (iter != formatMap.end()) + { + return iter->second; + } + else + { + UNREACHABLE(); + return GL_NONE; + } +} + +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.h new file mode 100644 index 0000000000..d77fccfe9c --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.h @@ -0,0 +1,79 @@ +// +// 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. +// + +// formatutils11.h: Queries for GL image formats and their translations to D3D11 +// formats. + +#ifndef LIBGLESV2_RENDERER_FORMATUTILS11_H_ +#define LIBGLESV2_RENDERER_FORMATUTILS11_H_ + +#include "libGLESv2/formatutils.h" + +namespace rx +{ + +class Renderer; + +namespace d3d11 +{ + +typedef std::set<DXGI_FORMAT> DXGIFormatSet; + +MipGenerationFunction GetMipGenerationFunction(DXGI_FORMAT format); +LoadImageFunction GetImageLoadFunction(GLenum internalFormat, GLenum type); + +GLuint GetFormatPixelBytes(DXGI_FORMAT format); +GLuint GetBlockWidth(DXGI_FORMAT format); +GLuint GetBlockHeight(DXGI_FORMAT format); +GLenum GetComponentType(DXGI_FORMAT format); + +GLuint GetDepthBits(DXGI_FORMAT format); +GLuint GetDepthOffset(DXGI_FORMAT format); +GLuint GetStencilBits(DXGI_FORMAT format); +GLuint GetStencilOffset(DXGI_FORMAT format); + +void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset); + +const DXGIFormatSet &GetAllUsedDXGIFormats(); + +ColorReadFunction GetColorReadFunction(DXGI_FORMAT format); +ColorCopyFunction GetFastCopyFunction(DXGI_FORMAT sourceFormat, GLenum destFormat, GLenum destType); + +} + +namespace gl_d3d11 +{ + +DXGI_FORMAT GetTexFormat(GLenum internalFormat); +DXGI_FORMAT GetSRVFormat(GLenum internalFormat); +DXGI_FORMAT GetRTVFormat(GLenum internalFormat); +DXGI_FORMAT GetDSVFormat(GLenum internalFormat); +DXGI_FORMAT GetRenderableFormat(GLenum internalFormat); + +DXGI_FORMAT GetSwizzleTexFormat(GLint internalFormat); +DXGI_FORMAT GetSwizzleSRVFormat(GLint internalFormat); +DXGI_FORMAT GetSwizzleRTVFormat(GLint internalFormat); + +bool RequiresTextureDataInitialization(GLint internalFormat); +InitializeTextureDataFunction GetTextureDataInitializationFunction(GLint internalFormat); + +VertexCopyFunction GetVertexCopyFunction(const gl::VertexFormat &vertexFormat); +size_t GetVertexElementSize(const gl::VertexFormat &vertexFormat); +VertexConversionType GetVertexConversionType(const gl::VertexFormat &vertexFormat); +DXGI_FORMAT GetNativeVertexFormat(const gl::VertexFormat &vertexFormat); + +} + +namespace d3d11_gl +{ + +GLenum GetInternalFormat(DXGI_FORMAT format); + +} + +} + +#endif // LIBGLESV2_RENDERER_FORMATUTILS11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp new file mode 100644 index 0000000000..d914a8201b --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp @@ -0,0 +1,692 @@ +#include "precompiled.h" +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// renderer11_utils.cpp: Conversion functions and other utility routines +// specific to the D3D11 renderer. + +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" +#include "common/debug.h" + +#ifndef D3D_FL9_1_DEFAULT_MAX_ANISOTROPY +# define D3D_FL9_1_DEFAULT_MAX_ANISOTROPY 2 +#endif +#ifndef D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT +# define D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT 1 +#endif +#ifndef D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT +# define D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT 4 +#endif +#ifndef D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION +# define D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION 512 +#endif +#ifndef D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION +# define D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION 4096 +#endif +#ifndef D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION +# define D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION 2048 +#endif +#ifndef D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION +# define D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 256 +#endif +#ifndef D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION +# define D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION 4096 +#endif +#ifndef D3D11_REQ_TEXTURECUBE_DIMENSION +# define D3D11_REQ_TEXTURECUBE_DIMENSION 16384 +#endif +#ifndef D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION +# define D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION 2048 +#endif +#ifndef D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION +# define D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 2048 +#endif + +namespace rx +{ + +namespace gl_d3d11 +{ + +D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha) +{ + D3D11_BLEND d3dBlend = D3D11_BLEND_ZERO; + + switch (glBlend) + { + case GL_ZERO: d3dBlend = D3D11_BLEND_ZERO; break; + case GL_ONE: d3dBlend = D3D11_BLEND_ONE; break; + case GL_SRC_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_SRC_ALPHA : D3D11_BLEND_SRC_COLOR); break; + case GL_ONE_MINUS_SRC_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_INV_SRC_ALPHA : D3D11_BLEND_INV_SRC_COLOR); break; + case GL_DST_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_DEST_COLOR); break; + case GL_ONE_MINUS_DST_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_INV_DEST_COLOR); break; + case GL_SRC_ALPHA: d3dBlend = D3D11_BLEND_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: d3dBlend = D3D11_BLEND_INV_SRC_ALPHA; break; + case GL_DST_ALPHA: d3dBlend = D3D11_BLEND_DEST_ALPHA; break; + case GL_ONE_MINUS_DST_ALPHA: d3dBlend = D3D11_BLEND_INV_DEST_ALPHA; break; + case GL_CONSTANT_COLOR: d3dBlend = D3D11_BLEND_BLEND_FACTOR; break; + case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3D11_BLEND_INV_BLEND_FACTOR; break; + case GL_CONSTANT_ALPHA: d3dBlend = D3D11_BLEND_BLEND_FACTOR; break; + case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3D11_BLEND_INV_BLEND_FACTOR; break; + case GL_SRC_ALPHA_SATURATE: d3dBlend = D3D11_BLEND_SRC_ALPHA_SAT; break; + default: UNREACHABLE(); + } + + return d3dBlend; +} + +D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp) +{ + D3D11_BLEND_OP d3dBlendOp = D3D11_BLEND_OP_ADD; + + switch (glBlendOp) + { + case GL_FUNC_ADD: d3dBlendOp = D3D11_BLEND_OP_ADD; break; + case GL_FUNC_SUBTRACT: d3dBlendOp = D3D11_BLEND_OP_SUBTRACT; break; + case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3D11_BLEND_OP_REV_SUBTRACT; break; + case GL_MIN: d3dBlendOp = D3D11_BLEND_OP_MIN; break; + case GL_MAX: d3dBlendOp = D3D11_BLEND_OP_MAX; break; + default: UNREACHABLE(); + } + + return d3dBlendOp; +} + +UINT8 ConvertColorMask(bool red, bool green, bool blue, bool alpha) +{ + UINT8 mask = 0; + if (red) + { + mask |= D3D11_COLOR_WRITE_ENABLE_RED; + } + if (green) + { + mask |= D3D11_COLOR_WRITE_ENABLE_GREEN; + } + if (blue) + { + mask |= D3D11_COLOR_WRITE_ENABLE_BLUE; + } + if (alpha) + { + mask |= D3D11_COLOR_WRITE_ENABLE_ALPHA; + } + return mask; +} + +D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode) +{ + D3D11_CULL_MODE cull = D3D11_CULL_NONE; + + if (cullEnabled) + { + switch (cullMode) + { + case GL_FRONT: cull = D3D11_CULL_FRONT; break; + case GL_BACK: cull = D3D11_CULL_BACK; break; + case GL_FRONT_AND_BACK: cull = D3D11_CULL_NONE; break; + default: UNREACHABLE(); + } + } + else + { + cull = D3D11_CULL_NONE; + } + + return cull; +} + +D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison) +{ + D3D11_COMPARISON_FUNC d3dComp = D3D11_COMPARISON_NEVER; + switch (comparison) + { + case GL_NEVER: d3dComp = D3D11_COMPARISON_NEVER; break; + case GL_ALWAYS: d3dComp = D3D11_COMPARISON_ALWAYS; break; + case GL_LESS: d3dComp = D3D11_COMPARISON_LESS; break; + case GL_LEQUAL: d3dComp = D3D11_COMPARISON_LESS_EQUAL; break; + case GL_EQUAL: d3dComp = D3D11_COMPARISON_EQUAL; break; + case GL_GREATER: d3dComp = D3D11_COMPARISON_GREATER; break; + case GL_GEQUAL: d3dComp = D3D11_COMPARISON_GREATER_EQUAL; break; + case GL_NOTEQUAL: d3dComp = D3D11_COMPARISON_NOT_EQUAL; break; + default: UNREACHABLE(); + } + + return d3dComp; +} + +D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled) +{ + return depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; +} + +UINT8 ConvertStencilMask(GLuint stencilmask) +{ + return static_cast<UINT8>(stencilmask); +} + +D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp) +{ + D3D11_STENCIL_OP d3dStencilOp = D3D11_STENCIL_OP_KEEP; + + switch (stencilOp) + { + case GL_ZERO: d3dStencilOp = D3D11_STENCIL_OP_ZERO; break; + case GL_KEEP: d3dStencilOp = D3D11_STENCIL_OP_KEEP; break; + case GL_REPLACE: d3dStencilOp = D3D11_STENCIL_OP_REPLACE; break; + case GL_INCR: d3dStencilOp = D3D11_STENCIL_OP_INCR_SAT; break; + case GL_DECR: d3dStencilOp = D3D11_STENCIL_OP_DECR_SAT; break; + case GL_INVERT: d3dStencilOp = D3D11_STENCIL_OP_INVERT; break; + case GL_INCR_WRAP: d3dStencilOp = D3D11_STENCIL_OP_INCR; break; + case GL_DECR_WRAP: d3dStencilOp = D3D11_STENCIL_OP_DECR; break; + default: UNREACHABLE(); + } + + return d3dStencilOp; +} + +D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy, GLenum comparisonMode) +{ + bool comparison = comparisonMode != GL_NONE; + + if (maxAnisotropy > 1.0f) + { + return D3D11_ENCODE_ANISOTROPIC_FILTER(static_cast<D3D11_COMPARISON_FUNC>(comparison)); + } + else + { + D3D11_FILTER_TYPE dxMin = D3D11_FILTER_TYPE_POINT; + D3D11_FILTER_TYPE dxMip = D3D11_FILTER_TYPE_POINT; + switch (minFilter) + { + case GL_NEAREST: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_POINT; break; + case GL_LINEAR: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_POINT; break; + case GL_NEAREST_MIPMAP_NEAREST: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_POINT; break; + case GL_LINEAR_MIPMAP_NEAREST: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_POINT; break; + case GL_NEAREST_MIPMAP_LINEAR: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_LINEAR; break; + case GL_LINEAR_MIPMAP_LINEAR: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_LINEAR; break; + default: UNREACHABLE(); + } + + D3D11_FILTER_TYPE dxMag = D3D11_FILTER_TYPE_POINT; + switch (magFilter) + { + case GL_NEAREST: dxMag = D3D11_FILTER_TYPE_POINT; break; + case GL_LINEAR: dxMag = D3D11_FILTER_TYPE_LINEAR; break; + default: UNREACHABLE(); + } + + return D3D11_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, static_cast<D3D11_COMPARISON_FUNC>(comparison)); + } +} + +D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap) +{ + switch (wrap) + { + case GL_REPEAT: return D3D11_TEXTURE_ADDRESS_WRAP; + case GL_CLAMP_TO_EDGE: return D3D11_TEXTURE_ADDRESS_CLAMP; + case GL_MIRRORED_REPEAT: return D3D11_TEXTURE_ADDRESS_MIRROR; + default: UNREACHABLE(); + } + + return D3D11_TEXTURE_ADDRESS_WRAP; +} + +D3D11_QUERY ConvertQueryType(GLenum queryType) +{ + switch (queryType) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: return D3D11_QUERY_OCCLUSION; + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: return D3D11_QUERY_SO_STATISTICS; + default: UNREACHABLE(); return D3D11_QUERY_EVENT; + } +} + +} + + +namespace d3d11_gl +{ + +static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, ID3D11Device *device) +{ + gl::TextureCaps textureCaps; + + DXGI_FORMAT textureFormat = gl_d3d11::GetTexFormat(internalFormat); + DXGI_FORMAT srvFormat = gl_d3d11::GetSRVFormat(internalFormat); + DXGI_FORMAT rtvFormat = gl_d3d11::GetRTVFormat(internalFormat); + DXGI_FORMAT dsvFormat = gl_d3d11::GetDSVFormat(internalFormat); + DXGI_FORMAT renderFormat = gl_d3d11::GetRenderableFormat(internalFormat); + + UINT formatSupport; + if (SUCCEEDED(device->CheckFormatSupport(textureFormat, &formatSupport))) + { + if (gl::GetDepthBits(internalFormat) > 0 || gl::GetStencilBits(internalFormat) > 0) + { + textureCaps.texturable = ((formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0); + } + else + { + textureCaps.texturable = ((formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0) && + ((formatSupport & D3D11_FORMAT_SUPPORT_TEXTURECUBE) != 0) && + ((formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE3D) != 0); + } + } + + if (SUCCEEDED(device->CheckFormatSupport(renderFormat, &formatSupport)) && + ((formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET) != 0)) + { + for (size_t sampleCount = 1; sampleCount <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; sampleCount++) + { + UINT qualityCount = 0; + if (SUCCEEDED(device->CheckMultisampleQualityLevels(renderFormat, sampleCount, &qualityCount)) && + qualityCount > 0) + { + textureCaps.sampleCounts.insert(sampleCount); + } + } + } + + textureCaps.filterable = SUCCEEDED(device->CheckFormatSupport(srvFormat, &formatSupport)) && + ((formatSupport & D3D11_FORMAT_SUPPORT_SHADER_SAMPLE)) != 0; + textureCaps.renderable = (SUCCEEDED(device->CheckFormatSupport(rtvFormat, &formatSupport)) && + ((formatSupport & D3D11_FORMAT_SUPPORT_RENDER_TARGET)) != 0) || + (SUCCEEDED(device->CheckFormatSupport(dsvFormat, &formatSupport)) && + ((formatSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL) != 0)); + + return textureCaps; +} + +static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if _MSC_VER >= 1700 + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if _MSC_VER >= 1700 + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_MAX_MAXANISOTROPY; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_MAX_MAXANISOTROPY; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: return 16; + + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_DEFAULT_MAX_ANISOTROPY; + + default: UNREACHABLE(); return 0; + } +} + +static bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if _MSC_VER >= 1700 + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateQuery + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: return true; + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel) +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateQuery + + switch (featureLevel) + { +#if _MSC_VER >= 1700 + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return true; + + default: UNREACHABLE(); return false; + } +} + +static bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel) +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateInputLayout + + switch (featureLevel) + { +#if _MSC_VER >= 1700 + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_9_3: return true; + + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static bool GetDerivativeInstructionSupport(D3D_FEATURE_LEVEL featureLevel) +{ + // http://msdn.microsoft.com/en-us/library/windows/desktop/bb509588.aspx states that shader model + // ps_2_x is required for the ddx (and other derivative functions). + + // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx states that feature level + // 9.3 supports shader model ps_2_x. + + switch (featureLevel) + { +#if _MSC_VER >= 1700 + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_9_3: return true; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel) +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateInputLayout + + switch (featureLevel) + { +#if _MSC_VER >= 1700 + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; + + // FIXME(geofflang): Work around NVIDIA driver bug by repacking buffers + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return 1; /* D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT; */ + + case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if _MSC_VER >= 1700 + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumCubeMapTextureSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if _MSC_VER >= 1700 + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURECUBE_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURECUBE_DIMENSION; + + case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximum2DTextureArraySize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if _MSC_VER >= 1700 + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if _MSC_VER >= 1700 + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if _MSC_VER >= 1700 + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_VIEWPORT_BOUNDS_MAX; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_VIEWPORT_BOUNDS_MAX; + + // No constants for D3D9 viewport size limits, use the maximum texture sizes + case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + default: UNREACHABLE(); return 0; + } +} + +void GenerateCaps(ID3D11Device *device, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions) +{ + const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats(); + for (gl::FormatSet::const_iterator internalFormat = allFormats.begin(); internalFormat != allFormats.end(); ++internalFormat) + { + gl::TextureCaps textureCaps = GenerateTextureFormatCaps(*internalFormat, device); + textureCapsMap->insert(*internalFormat, textureCaps); + } + + D3D_FEATURE_LEVEL featureLevel = device->GetFeatureLevel(); + + // GL core feature limits + caps->maxElementIndex = static_cast<GLint64>(std::numeric_limits<unsigned int>::max()); + caps->max3DTextureSize = GetMaximum3DTextureSize(featureLevel); + caps->max2DTextureSize = GetMaximum2DTextureSize(featureLevel); + caps->maxCubeMapTextureSize = GetMaximumCubeMapTextureSize(featureLevel); + caps->maxArrayTextureLayers = GetMaximum2DTextureArraySize(featureLevel); + + // Unimplemented, set to minimum required + caps->maxLODBias = 2.0f; + + // No specific limits on render target size, maximum 2D texture size is equivalent + caps->maxRenderbufferSize = caps->max2DTextureSize; + + // Maximum draw buffers and color attachments are the same, max color attachments could eventually be + // increased to 16 + caps->maxDrawBuffers = GetMaximumSimultaneousRenderTargets(featureLevel); + caps->maxColorAttachments = GetMaximumSimultaneousRenderTargets(featureLevel); + + // D3D11 has the same limit for viewport width and height + caps->maxViewportWidth = GetMaximumViewportSize(featureLevel); + caps->maxViewportHeight = caps->maxViewportWidth; + + // Choose a reasonable maximum, enforced in the shader. + caps->minAliasedPointSize = 1.0f; + caps->maxAliasedPointSize = 1024.0f; + + // Wide lines not supported + caps->minAliasedLineWidth = 1.0f; + caps->maxAliasedLineWidth = 1.0f; + + // GL extension support + extensions->setTextureExtensionSupport(*textureCapsMap); + extensions->elementIndexUint = true; + extensions->packedDepthStencil = true; + extensions->getProgramBinary = true; + extensions->rgb8rgba8 = true; + extensions->readFormatBGRA = true; + extensions->pixelBufferObject = true; + extensions->mapBuffer = true; + extensions->mapBufferRange = true; + extensions->textureNPOT = GetNPOTTextureSupport(featureLevel); + extensions->drawBuffers = GetMaximumSimultaneousRenderTargets(featureLevel) > 1; + extensions->textureStorage = true; + extensions->textureFilterAnisotropic = true; + extensions->maxTextureAnisotropy = GetMaximumAnisotropy(featureLevel); + extensions->occlusionQueryBoolean = GetOcclusionQuerySupport(featureLevel); + extensions->fence = GetEventQuerySupport(featureLevel); + extensions->timerQuery = false; // Unimplemented + extensions->robustness = true; + extensions->blendMinMax = true; + extensions->framebufferBlit = true; + extensions->framebufferMultisample = true; + extensions->instancedArrays = GetInstancingSupport(featureLevel); + extensions->packReverseRowOrder = true; + extensions->standardDerivatives = GetDerivativeInstructionSupport(featureLevel); + extensions->shaderTextureLOD = true; + extensions->fragDepth = true; + extensions->textureUsage = true; // This could be false since it has no effect in D3D11 + extensions->translatedShaderSource = true; +} + +} + +namespace d3d11 +{ + +void GenerateInitialTextureData(GLint internalFormat, GLuint width, GLuint height, GLuint depth, + GLuint mipLevels, std::vector<D3D11_SUBRESOURCE_DATA> *outSubresourceData, + std::vector< std::vector<BYTE> > *outData) +{ + InitializeTextureDataFunction initializeFunc = gl_d3d11::GetTextureDataInitializationFunction(internalFormat); + DXGI_FORMAT dxgiFormat = gl_d3d11::GetTexFormat(internalFormat); + + outSubresourceData->resize(mipLevels); + outData->resize(mipLevels); + + for (unsigned int i = 0; i < mipLevels; i++) + { + unsigned int mipWidth = std::max(width >> i, 1U); + unsigned int mipHeight = std::max(height >> i, 1U); + unsigned int mipDepth = std::max(depth >> i, 1U); + + unsigned int rowWidth = d3d11::GetFormatPixelBytes(dxgiFormat) * mipWidth; + unsigned int imageSize = rowWidth * height; + + outData->at(i).resize(rowWidth * mipHeight * mipDepth); + initializeFunc(mipWidth, mipHeight, mipDepth, outData->at(i).data(), rowWidth, imageSize); + + outSubresourceData->at(i).pSysMem = outData->at(i).data(); + outSubresourceData->at(i).SysMemPitch = rowWidth; + outSubresourceData->at(i).SysMemSlicePitch = imageSize; + } +} + +void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v) +{ + vertex->x = x; + vertex->y = y; + vertex->u = u; + vertex->v = v; +} + +void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, float x, float y, + unsigned int layer, float u, float v, float s) +{ + vertex->x = x; + vertex->y = y; + vertex->l = layer; + vertex->u = u; + vertex->v = v; + vertex->s = s; +} + +HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name) +{ +#if !defined(__MINGW32__) && defined(_DEBUG) + return resource->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(name), name); +#else + return S_OK; +#endif +} + +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.h new file mode 100644 index 0000000000..4de9bfa86d --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.h @@ -0,0 +1,173 @@ +// +// 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. +// + +// renderer11_utils.h: Conversion functions and other utility routines +// specific to the D3D11 renderer. + +#ifndef LIBGLESV2_RENDERER_RENDERER11_UTILS_H +#define LIBGLESV2_RENDERER_RENDERER11_UTILS_H + +#include "libGLESv2/angletypes.h" +#include "libGLESv2/Caps.h" + +namespace rx +{ + +namespace gl_d3d11 +{ + +D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha); +D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp); +UINT8 ConvertColorMask(bool maskRed, bool maskGreen, bool maskBlue, bool maskAlpha); + +D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode); + +D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison); +D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled); +UINT8 ConvertStencilMask(GLuint stencilmask); +D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp); + +D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy, GLenum comparisonMode); +D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap); + +D3D11_QUERY ConvertQueryType(GLenum queryType); + +} + +namespace d3d11_gl +{ + +void GenerateCaps(ID3D11Device *device, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions); + +} + +namespace d3d11 +{ + +void GenerateInitialTextureData(GLint internalFormat, GLuint width, GLuint height, GLuint depth, + GLuint mipLevels, std::vector<D3D11_SUBRESOURCE_DATA> *outSubresourceData, + std::vector< std::vector<BYTE> > *outData); + +struct PositionTexCoordVertex +{ + float x, y; + float u, v; +}; +void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v); + +struct PositionLayerTexCoord3DVertex +{ + float x, y; + unsigned int l; + float u, v, s; +}; +void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, float x, float y, + unsigned int layer, float u, float v, float s); + +template <typename T> +struct PositionDepthColorVertex +{ + float x, y, z; + T r, g, b, a; +}; + +template <typename T> +void SetPositionDepthColorVertex(PositionDepthColorVertex<T>* vertex, float x, float y, float z, + const gl::Color<T> &color) +{ + vertex->x = x; + vertex->y = y; + vertex->z = z; + vertex->r = color.red; + vertex->g = color.green; + vertex->b = color.blue; + vertex->a = color.alpha; +} + +HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name); + +template <typename outType> +outType* DynamicCastComObject(IUnknown* object) +{ + outType *outObject = NULL; + HRESULT result = object->QueryInterface(__uuidof(outType), reinterpret_cast<void**>(&outObject)); + if (SUCCEEDED(result)) + { + return outObject; + } + else + { + SafeRelease(outObject); + return NULL; + } +} + +inline bool isDeviceLostError(HRESULT errorCode) +{ + switch (errorCode) + { + case DXGI_ERROR_DEVICE_HUNG: + case DXGI_ERROR_DEVICE_REMOVED: + case DXGI_ERROR_DEVICE_RESET: + case DXGI_ERROR_DRIVER_INTERNAL_ERROR: + case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE: + return true; + default: + return false; + } +} + +template <unsigned int N> +inline ID3D11VertexShader *CompileVS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) +{ + ID3D11VertexShader *vs = NULL; + HRESULT result = device->CreateVertexShader(byteCode, N, NULL, &vs); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + SetDebugName(vs, name); + return vs; +} + +template <unsigned int N> +inline ID3D11GeometryShader *CompileGS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) +{ + ID3D11GeometryShader *gs = NULL; + HRESULT result = device->CreateGeometryShader(byteCode, N, NULL, &gs); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + SetDebugName(gs, name); + return gs; +} + +template <unsigned int N> +inline ID3D11PixelShader *CompilePS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) +{ + ID3D11PixelShader *ps = NULL; + HRESULT result = device->CreatePixelShader(byteCode, N, NULL, &ps); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + SetDebugName(ps, name); + return ps; +} + +// Copy data to small D3D11 buffers, such as for small constant buffers, which use one struct to +// represent an entire buffer. +template <class T> +inline void SetBufferData(ID3D11DeviceContext *context, ID3D11Buffer *constantBuffer, const T &value) +{ + D3D11_MAPPED_SUBRESOURCE mappedResource; + context->Map(constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + + memcpy(mappedResource.pData, &value, sizeof(T)); + + context->Unmap(constantBuffer, 0); +} + +} + +} + +#endif // LIBGLESV2_RENDERER_RENDERER11_UTILS_H diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl new file mode 100644 index 0000000000..20e6623a30 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl @@ -0,0 +1,76 @@ +Buffer<float4> Buffer4F : register(t0); +Buffer<int4> Buffer4I : register(t0); +Buffer<uint4> Buffer4UI : register(t0); + +struct VS_OUTPUT +{ + float4 position : SV_Position; + uint index : TEXCOORD0; + uint slice : LAYER; +}; + +struct GS_OUTPUT +{ + float4 position : SV_Position; + uint index : TEXCOORD0; + uint slice : SV_RenderTargetArrayIndex; +}; + +cbuffer BufferCopyParams : register(b0) +{ + uint FirstPixelOffset; + uint PixelsPerRow; + uint RowStride; + uint RowsPerSlice; + float2 PositionOffset; + float2 PositionScale; + int2 TexLocationOffset; + int2 TexLocationScale; +} + +void ComputePositionAndIndex(uint vertexID, out VS_OUTPUT outVertex) +{ + uint PixelsPerSlice = PixelsPerRow * RowsPerSlice; + uint SliceStride = RowStride * RowsPerSlice; + + uint slice = vertexID / PixelsPerSlice; + uint sliceOffset = slice * PixelsPerSlice; + uint row = (vertexID - sliceOffset) / PixelsPerRow; + uint col = vertexID - sliceOffset - (row * PixelsPerRow); + + float2 coords = float2(float(col), float(row)); + + outVertex.position = float4(PositionOffset + PositionScale * coords, 0.0f, 1.0f); + outVertex.index = FirstPixelOffset + slice * SliceStride + row * RowStride + col; + outVertex.slice = slice; +} + +void VS_BufferToTexture(in uint vertexID : SV_VertexID, out VS_OUTPUT outVertex) +{ + ComputePositionAndIndex(vertexID, outVertex); +} + +[maxvertexcount(1)] +void GS_BufferToTexture(point VS_OUTPUT inVertex[1], inout PointStream<GS_OUTPUT> outStream) +{ + GS_OUTPUT outVertex; + outVertex.position = inVertex[0].position; + outVertex.index = inVertex[0].index; + outVertex.slice = inVertex[0].slice; + outStream.Append(outVertex); +} + +float4 PS_BufferToTexture_4F(in float4 inPosition : SV_Position, in uint inIndex : TEXCOORD0) : SV_Target +{ + return Buffer4F.Load(inIndex); +} + +int4 PS_BufferToTexture_4I(in float4 inPosition : SV_Position, in uint inIndex : TEXCOORD0) : SV_Target +{ + return Buffer4I.Load(inIndex); +} + +uint4 PS_BufferToTexture_4UI(in float4 inPosition : SV_Position, in uint inIndex : TEXCOORD0) : SV_Target +{ + return Buffer4UI.Load(inIndex); +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl new file mode 100644 index 0000000000..b4cf38076e --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl @@ -0,0 +1,106 @@ +// Assume we are in SM4+, which has 8 color outputs + +void VS_ClearFloat( in float3 inPosition : POSITION, in float4 inColor : COLOR, + out float4 outPosition : SV_POSITION, out float4 outColor : COLOR) +{ + outPosition = float4(inPosition, 1.0f); + outColor = inColor; +} + +struct PS_OutputFloat +{ + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float4 color2 : SV_TARGET2; + float4 color3 : SV_TARGET3; +#if SM4 + float4 color4 : SV_TARGET4; + float4 color5 : SV_TARGET5; + float4 color6 : SV_TARGET6; + float4 color7 : SV_TARGET7; +#endif +}; + +PS_OutputFloat PS_ClearFloat(in float4 inPosition : SV_POSITION, in float4 inColor : COLOR) +{ + PS_OutputFloat outColor; + outColor.color0 = inColor; + outColor.color1 = inColor; + outColor.color2 = inColor; + outColor.color3 = inColor; +#if SM4 + outColor.color4 = inColor; + outColor.color5 = inColor; + outColor.color6 = inColor; + outColor.color7 = inColor; +#endif + return outColor; +} + + +void VS_ClearUint( in float3 inPosition : POSITION, in uint4 inColor : COLOR, + out float4 outPosition : SV_POSITION, out uint4 outColor : COLOR) +{ + outPosition = float4(inPosition, 1.0f); + outColor = inColor; +} + +struct PS_OutputUint +{ + uint4 color0 : SV_TARGET0; + uint4 color1 : SV_TARGET1; + uint4 color2 : SV_TARGET2; + uint4 color3 : SV_TARGET3; + uint4 color4 : SV_TARGET4; + uint4 color5 : SV_TARGET5; + uint4 color6 : SV_TARGET6; + uint4 color7 : SV_TARGET7; +}; + +PS_OutputUint PS_ClearUint(in float4 inPosition : SV_POSITION, in uint4 inColor : COLOR) +{ + PS_OutputUint outColor; + outColor.color0 = inColor; + outColor.color1 = inColor; + outColor.color2 = inColor; + outColor.color3 = inColor; + outColor.color4 = inColor; + outColor.color5 = inColor; + outColor.color6 = inColor; + outColor.color7 = inColor; + return outColor; +} + + +void VS_ClearSint( in float3 inPosition : POSITION, in int4 inColor : COLOR, + out float4 outPosition : SV_POSITION, out int4 outColor : COLOR) +{ + outPosition = float4(inPosition, 1.0f); + outColor = inColor; +} + +struct PS_OutputSint +{ + int4 color0 : SV_TARGET0; + int4 color1 : SV_TARGET1; + int4 color2 : SV_TARGET2; + int4 color3 : SV_TARGET3; + int4 color4 : SV_TARGET4; + int4 color5 : SV_TARGET5; + int4 color6 : SV_TARGET6; + int4 color7 : SV_TARGET7; +}; + +PS_OutputSint PS_ClearSint(in float4 inPosition : SV_POSITION, in int4 inColor : COLOR) +{ + PS_OutputSint outColor; + outColor.color0 = inColor; + outColor.color1 = inColor; + outColor.color2 = inColor; + outColor.color3 = inColor; + outColor.color4 = inColor; + outColor.color5 = inColor; + outColor.color6 = inColor; + outColor.color7 = inColor; + return outColor; +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl new file mode 100644 index 0000000000..8671c39fb7 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl @@ -0,0 +1,111 @@ +Texture2D<float4> TextureF : register(t0); +Texture2D<uint4> TextureUI : register(t0); +Texture2D<int4> TextureI : register(t0); + +SamplerState Sampler : register(s0); + +void VS_Passthrough2D( in float2 inPosition : POSITION, in float2 inTexCoord : TEXCOORD0, + out float4 outPosition : SV_POSITION, out float2 outTexCoord : TEXCOORD0) +{ + outPosition = float4(inPosition, 0.0f, 1.0f); + outTexCoord = inTexCoord; +} + +float PS_PassthroughDepth2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_DEPTH +{ + return TextureF.Sample(Sampler, inTexCoord).r; +} + +float4 PS_PassthroughRGBA2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return TextureF.Sample(Sampler, inTexCoord).rgba; +} + +uint4 PS_PassthroughRGBA2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI.GetDimensions(size.x, size.y); + + return TextureUI.Load(int3(size * inTexCoord, 0)).rgba; +} + +int4 PS_PassthroughRGBA2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI.GetDimensions(size.x, size.y); + + return TextureI.Load(int3(size * inTexCoord, 0)).rgba; +} + +float4 PS_PassthroughRGB2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, inTexCoord).rgb, 1.0f); +} + +uint4 PS_PassthroughRGB2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI.GetDimensions(size.x, size.y); + + return uint4(TextureUI.Load(int3(size * inTexCoord, 0)).rgb, 0); +} + +int4 PS_PassthroughRGB2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI.GetDimensions(size.x, size.y); + + return int4(TextureI.Load(int3(size * inTexCoord, 0)).rgb, 0); +} + +float4 PS_PassthroughRG2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, inTexCoord).rg, 0.0f, 1.0f); +} + +uint4 PS_PassthroughRG2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI.GetDimensions(size.x, size.y); + + return uint4(TextureUI.Load(int3(size * inTexCoord, 0)).rg, 0, 0); +} + +int4 PS_PassthroughRG2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI.GetDimensions(size.x, size.y); + + return int4(TextureI.Load(int3(size * inTexCoord, 0)).rg, 0, 0); +} + +float4 PS_PassthroughR2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, inTexCoord).r, 0.0f, 0.0f, 1.0f); +} + +uint4 PS_PassthroughR2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI.GetDimensions(size.x, size.y); + + return uint4(TextureUI.Load(int3(size * inTexCoord, 0)).r, 0, 0, 0); +} + +int4 PS_PassthroughR2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI.GetDimensions(size.x, size.y); + + return int4(TextureI.Load(int3(size * inTexCoord, 0)).r, 0, 0, 0); +} + +float4 PS_PassthroughLum2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, inTexCoord).rrr, 1.0f); +} + +float4 PS_PassthroughLumAlpha2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return TextureF.Sample(Sampler, inTexCoord).rrra; +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl new file mode 100644 index 0000000000..c23c9032ec --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl @@ -0,0 +1,146 @@ +Texture3D<float4> TextureF : register(t0); +Texture3D<uint4> TextureUI : register(t0); +Texture3D<int4> TextureI : register(t0); + +SamplerState Sampler : register(s0); + +struct VS_INPUT +{ + float2 Position : POSITION; + uint Layer : LAYER; + float3 TexCoord : TEXCOORD; +}; + +struct VS_OUTPUT +{ + float4 Position : SV_POSITION; + uint Layer : LAYER; + float3 TexCoord : TEXCOORD; +}; + +struct GS_OUTPUT +{ + float4 Position : SV_POSITION; + uint Layer : SV_RENDERTARGETARRAYINDEX; + float3 TexCoord : TEXCOORD; +}; + +VS_OUTPUT VS_Passthrough3D(VS_INPUT input) +{ + VS_OUTPUT output; + + output.Position = float4(input.Position, 0.0f, 1.0f); + output.Layer = input.Layer; + output.TexCoord = input.TexCoord; + + return output; +} + +[maxvertexcount(3)] +void GS_Passthrough3D(triangle VS_OUTPUT input[3], inout TriangleStream<GS_OUTPUT> outputStream) +{ + GS_OUTPUT output; + + for (int i = 0; i < 3; i++) + { + output.Position = input[i].Position; + output.Layer = input[i].Layer; + output.TexCoord = input[i].TexCoord; + + outputStream.Append(output); + } +} + +float4 PS_PassthroughRGBA3D(GS_OUTPUT input) : SV_TARGET0 +{ + return TextureF.Sample(Sampler, input.TexCoord).rgba; +} + +uint4 PS_PassthroughRGBA3DUI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureUI.GetDimensions(size.x, size.y, size.z); + + return TextureUI.Load(int4(size * input.TexCoord, 0)).rgba; +} + +int4 PS_PassthroughRGBA3DI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureI.GetDimensions(size.x, size.y, size.z); + + return TextureI.Load(int4(size * input.TexCoord, 0)).rgba; +} + +float4 PS_PassthroughRGB3D(GS_OUTPUT input) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, input.TexCoord).rgb, 1.0f); +} + +uint4 PS_PassthroughRGB3DUI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureUI.GetDimensions(size.x, size.y, size.z); + + return uint4(TextureUI.Load(int4(size * input.TexCoord, 0)).rgb, 0); +} + +int4 PS_PassthroughRGB3DI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureI.GetDimensions(size.x, size.y, size.z); + + return int4(TextureI.Load(int4(size * input.TexCoord, 0)).rgb, 0); +} + +float4 PS_PassthroughRG3D(GS_OUTPUT input) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, input.TexCoord).rg, 0.0f, 1.0f); +} + +uint4 PS_PassthroughRG3DUI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureUI.GetDimensions(size.x, size.y, size.z); + + return uint4(TextureUI.Load(int4(size * input.TexCoord, 0)).rg, 0, 0); +} + +int4 PS_PassthroughRG3DI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureI.GetDimensions(size.x, size.y, size.z); + + return int4(TextureI.Load(int4(size * input.TexCoord, 0)).rg, 0, 0); +} + +float4 PS_PassthroughR3D(GS_OUTPUT input) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, input.TexCoord).r, 0.0f, 0.0f, 1.0f); +} + +uint4 PS_PassthroughR3DUI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureUI.GetDimensions(size.x, size.y, size.z); + + return uint4(TextureUI.Load(int4(size * input.TexCoord, 0)).r, 0, 0, 0); +} + +int4 PS_PassthroughR3DI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureI.GetDimensions(size.x, size.y, size.z); + + return int4(TextureI.Load(int4(size * input.TexCoord, 0)).r, 0, 0, 0); +} + +float4 PS_PassthroughLum3D(GS_OUTPUT input) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, input.TexCoord).rrr, 1.0f); +} + +float4 PS_PassthroughLumAlpha3D(GS_OUTPUT input) : SV_TARGET0 +{ + return TextureF.Sample(Sampler, input.TexCoord).rrra; +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Swizzle11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Swizzle11.hlsl new file mode 100644 index 0000000000..505e222137 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Swizzle11.hlsl @@ -0,0 +1,99 @@ +Texture2D<float4> TextureF2D : register(t0); +Texture2D<uint4> TextureUI2D : register(t0); +Texture2D<int4> TextureI2D : register(t0); + +Texture3D<float4> TextureF3D : register(t0); +Texture3D<uint4> TextureUI3D : register(t0); +Texture3D<int4> TextureI3D : register(t0); + +Texture2DArray<float4> TextureF2DArray : register(t0); +Texture2DArray<uint4> TextureUI2DArray : register(t0); +Texture2DArray<int4> TextureI2DArray : register(t0); + +SamplerState Sampler : register(s0); + +cbuffer SwizzleProperties : register(b0) +{ + uint4 SwizzleIndices : packoffset(c0); +} + +float4 SwizzleLookup(in float4 sample) +{ + float lookup[6] = { sample[0], sample[1], sample[2], sample[3], 0.0f, 1.0f }; + return float4(lookup[SwizzleIndices[0]], lookup[SwizzleIndices[1]], lookup[SwizzleIndices[2]], lookup[SwizzleIndices[3]]); +} + +int4 SwizzleLookup(in int4 sample) +{ + int lookup[6] = { sample[0], sample[1], sample[2], sample[3], 0.0f, 1.0f }; + return int4(lookup[SwizzleIndices[0]], lookup[SwizzleIndices[1]], lookup[SwizzleIndices[2]], lookup[SwizzleIndices[3]]); +} + +uint4 SwizzleLookup(in uint4 sample) +{ + uint lookup[6] = { sample[0], sample[1], sample[2], sample[3], 0.0f, 1.0f }; + return uint4(lookup[SwizzleIndices[0]], lookup[SwizzleIndices[1]], lookup[SwizzleIndices[2]], lookup[SwizzleIndices[3]]); +} + +float4 PS_SwizzleF2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return SwizzleLookup(TextureF2D.Sample(Sampler, inTexCoord)); +} + +int4 PS_SwizzleI2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI2D.GetDimensions(size.x, size.y); + + return SwizzleLookup(TextureI2D.Load(int3(size * inTexCoord, 0))); +} + +uint4 PS_SwizzleUI2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI2D.GetDimensions(size.x, size.y); + + return SwizzleLookup(TextureUI2D.Load(int3(size * inTexCoord, 0))); +} + +float4 PS_SwizzleF3D(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return SwizzleLookup(TextureF3D.Sample(Sampler, inTexCoord)); +} + +int4 PS_SwizzleI3D(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint3 size; + TextureI3D.GetDimensions(size.x, size.y, size.z); + + return SwizzleLookup(TextureI3D.Load(int4(size * inTexCoord, 0))); +} + +uint4 PS_SwizzleUI3D(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint3 size; + TextureUI3D.GetDimensions(size.x, size.y, size.z); + + return SwizzleLookup(TextureUI3D.Load(int4(size * inTexCoord, 0))); +} + +float4 PS_SwizzleF2DArray(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return SwizzleLookup(TextureF2DArray.Sample(Sampler, float3(inTexCoord.xy, inLayer))); +} + +int4 PS_SwizzleI2DArray(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint3 size; + TextureI2DArray.GetDimensions(size.x, size.y, size.z); + + return SwizzleLookup(TextureI2DArray.Load(int4(size.xy * inTexCoord.xy, inLayer, 0))); +} + +uint4 PS_SwizzleUI2DArray(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint3 size; + TextureUI2DArray.GetDimensions(size.x, size.y, size.z); + + return SwizzleLookup(TextureUI2DArray.Load(int4(size.xy * inTexCoord.xy, inLayer, 0))); +} |