blob: 0767bc99f309e1976add862fdd2589197c8d2232 [file] [log] [blame]
//
// 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 LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_
#define LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_
#include <array>
#include <functional>
#include <vector>
#include "common/Color.h"
#include "libANGLE/Caps.h"
#include "libANGLE/Error.h"
#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
#include "libANGLE/renderer/d3d/RendererD3D.h"
namespace gl
{
class FramebufferAttachment;
}
namespace rx
{
class Renderer11;
class RenderTarget11;
struct Renderer11DeviceCaps;
using RenderTargetArray = std::array<RenderTarget11 *, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>;
using RTVArray = std::array<ID3D11RenderTargetView *, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>;
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);
UINT ConvertMaxAnisotropy(float maxAnisotropy, D3D_FEATURE_LEVEL featureLevel);
D3D11_QUERY ConvertQueryType(GLenum queryType);
UINT8 GetColorMask(const gl::InternalFormat *formatInfo);
} // namespace gl_d3d11
namespace d3d11_gl
{
unsigned int GetReservedVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel);
unsigned int GetReservedFragmentUniformVectors(D3D_FEATURE_LEVEL featureLevel);
gl::Version GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel);
void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, const Renderer11DeviceCaps &renderer11DeviceCaps, gl::Caps *caps,
gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions, gl::Limitations *limitations);
} // namespace d3d11_gl
namespace d3d11
{
enum ANGLED3D11DeviceType
{
ANGLE_D3D11_DEVICE_TYPE_UNKNOWN,
ANGLE_D3D11_DEVICE_TYPE_HARDWARE,
ANGLE_D3D11_DEVICE_TYPE_SOFTWARE_REF_OR_NULL,
ANGLE_D3D11_DEVICE_TYPE_WARP,
};
ANGLED3D11DeviceType GetDeviceType(ID3D11Device *device);
void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset);
void GenerateInitialTextureData(GLint internalFormat,
const Renderer11DeviceCaps &renderer11DeviceCaps,
GLuint width,
GLuint height,
GLuint depth,
GLuint mipLevels,
std::vector<D3D11_SUBRESOURCE_DATA> *outSubresourceData,
std::vector<std::vector<BYTE>> *outData);
UINT GetPrimitiveRestartIndex();
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);
struct PositionVertex
{
float x, y, z, w;
};
struct BlendStateKey
{
gl::BlendState blendState;
bool mrt;
uint8_t rtvMasks[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT];
};
HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name);
template <typename T>
HRESULT SetDebugName(angle::ComPtr<T> &resource, const char *name)
{
return SetDebugName(resource.Get(), name);
}
template <typename outType>
outType* DynamicCastComObject(IUnknown* object)
{
outType *outObject = nullptr;
HRESULT result = object->QueryInterface(__uuidof(outType), reinterpret_cast<void**>(&outObject));
if (SUCCEEDED(result))
{
return outObject;
}
else
{
SafeRelease(outObject);
return nullptr;
}
}
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;
}
}
inline ID3D11VertexShader *CompileVS(ID3D11Device *device, const BYTE *byteCode, size_t N, const char *name)
{
ID3D11VertexShader *vs = nullptr;
HRESULT result = device->CreateVertexShader(byteCode, N, nullptr, &vs);
ASSERT(SUCCEEDED(result));
if (SUCCEEDED(result))
{
SetDebugName(vs, name);
return vs;
}
return nullptr;
}
template <unsigned int N>
ID3D11VertexShader *CompileVS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name)
{
return CompileVS(device, byteCode, N, name);
}
inline ID3D11GeometryShader *CompileGS(ID3D11Device *device, const BYTE *byteCode, size_t N, const char *name)
{
ID3D11GeometryShader *gs = nullptr;
HRESULT result = device->CreateGeometryShader(byteCode, N, nullptr, &gs);
ASSERT(SUCCEEDED(result));
if (SUCCEEDED(result))
{
SetDebugName(gs, name);
return gs;
}
return nullptr;
}
template <unsigned int N>
ID3D11GeometryShader *CompileGS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name)
{
return CompileGS(device, byteCode, N, name);
}
inline ID3D11PixelShader *CompilePS(ID3D11Device *device, const BYTE *byteCode, size_t N, const char *name)
{
ID3D11PixelShader *ps = nullptr;
HRESULT result = device->CreatePixelShader(byteCode, N, nullptr, &ps);
ASSERT(SUCCEEDED(result));
if (SUCCEEDED(result))
{
SetDebugName(ps, name);
return ps;
}
return nullptr;
}
template <unsigned int N>
ID3D11PixelShader *CompilePS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name)
{
return CompilePS(device, byteCode, N, name);
}
template <typename ResourceType>
class LazyResource : angle::NonCopyable
{
public:
LazyResource() : mResource(nullptr), mAssociatedDevice(nullptr) {}
virtual ~LazyResource() { release(); }
virtual ResourceType *resolve(ID3D11Device *device) = 0;
void release() { SafeRelease(mResource); }
protected:
void checkAssociatedDevice(ID3D11Device *device);
ResourceType *mResource;
ID3D11Device *mAssociatedDevice;
};
template <typename ResourceType>
void LazyResource<ResourceType>::checkAssociatedDevice(ID3D11Device *device)
{
ASSERT(mAssociatedDevice == nullptr || device == mAssociatedDevice);
mAssociatedDevice = device;
}
template <typename D3D11ShaderType>
class LazyShader final : public LazyResource<D3D11ShaderType>
{
public:
// All parameters must be constexpr. Not supported in VS2013.
LazyShader(const BYTE *byteCode,
size_t byteCodeSize,
const char *name)
: mByteCode(byteCode),
mByteCodeSize(byteCodeSize),
mName(name)
{
}
D3D11ShaderType *resolve(ID3D11Device *device) override;
private:
const BYTE *mByteCode;
size_t mByteCodeSize;
const char *mName;
};
template <>
inline ID3D11VertexShader *LazyShader<ID3D11VertexShader>::resolve(ID3D11Device *device)
{
checkAssociatedDevice(device);
if (mResource == nullptr)
{
mResource = CompileVS(device, mByteCode, mByteCodeSize, mName);
}
return mResource;
}
template <>
inline ID3D11GeometryShader *LazyShader<ID3D11GeometryShader>::resolve(ID3D11Device *device)
{
checkAssociatedDevice(device);
if (mResource == nullptr)
{
mResource = CompileGS(device, mByteCode, mByteCodeSize, mName);
}
return mResource;
}
template <>
inline ID3D11PixelShader *LazyShader<ID3D11PixelShader>::resolve(ID3D11Device *device)
{
checkAssociatedDevice(device);
if (mResource == nullptr)
{
mResource = CompilePS(device, mByteCode, mByteCodeSize, mName);
}
return mResource;
}
class LazyInputLayout final : public LazyResource<ID3D11InputLayout>
{
public:
LazyInputLayout(const D3D11_INPUT_ELEMENT_DESC *inputDesc,
size_t inputDescLen,
const BYTE *byteCode,
size_t byteCodeLen,
const char *debugName);
ID3D11InputLayout *resolve(ID3D11Device *device) override;
private:
std::vector<D3D11_INPUT_ELEMENT_DESC> mInputDesc;
size_t mByteCodeLen;
const BYTE *mByteCode;
const char *mDebugName;
};
class LazyBlendState final : public LazyResource<ID3D11BlendState>
{
public:
LazyBlendState(const D3D11_BLEND_DESC &desc, const char *debugName);
ID3D11BlendState *resolve(ID3D11Device *device) override;
private:
D3D11_BLEND_DESC mDesc;
const char *mDebugName;
};
// Copy data to small D3D11 buffers, such as for small constant buffers, which use one struct to
// represent an entire buffer.
template <class T>
void SetBufferData(ID3D11DeviceContext *context, ID3D11Buffer *constantBuffer, const T &value)
{
D3D11_MAPPED_SUBRESOURCE mappedResource = {};
HRESULT result = context->Map(constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
ASSERT(SUCCEEDED(result));
if (SUCCEEDED(result))
{
memcpy(mappedResource.pData, &value, sizeof(T));
context->Unmap(constantBuffer, 0);
}
}
angle::WorkaroundsD3D GenerateWorkarounds(const Renderer11DeviceCaps &deviceCaps,
const DXGI_ADAPTER_DESC &adapterDesc);
enum ReservedConstantBufferSlot
{
RESERVED_CONSTANT_BUFFER_SLOT_DEFAULT_UNIFORM_BLOCK = 0,
RESERVED_CONSTANT_BUFFER_SLOT_DRIVER = 1,
RESERVED_CONSTANT_BUFFER_SLOT_COUNT = 2
};
void InitConstantBufferDesc(D3D11_BUFFER_DESC *constantBufferDescription, size_t byteWidth);
} // namespace d3d11
// A helper class which wraps a 2D or 3D texture.
class TextureHelper11 : angle::NonCopyable
{
public:
TextureHelper11();
TextureHelper11(TextureHelper11 &&toCopy);
~TextureHelper11();
TextureHelper11 &operator=(TextureHelper11 &&texture);
static TextureHelper11 MakeAndReference(ID3D11Resource *genericResource,
const d3d11::Format &formatSet);
static TextureHelper11 MakeAndPossess2D(ID3D11Texture2D *texToOwn,
const d3d11::Format &formatSet);
static TextureHelper11 MakeAndPossess3D(ID3D11Texture3D *texToOwn,
const d3d11::Format &formatSet);
GLenum getTextureType() const { return mTextureType; }
gl::Extents getExtents() const { return mExtents; }
DXGI_FORMAT getFormat() const { return mFormat; }
const d3d11::Format &getFormatSet() const { return *mFormatSet; }
int getSampleCount() const { return mSampleCount; }
ID3D11Texture2D *getTexture2D() const { return mTexture2D; }
ID3D11Texture3D *getTexture3D() const { return mTexture3D; }
ID3D11Resource *getResource() const;
bool valid() const;
private:
void reset();
void initDesc();
GLenum mTextureType;
gl::Extents mExtents;
DXGI_FORMAT mFormat;
const d3d11::Format *mFormatSet;
int mSampleCount;
ID3D11Texture2D *mTexture2D;
ID3D11Texture3D *mTexture3D;
};
enum class StagingAccess
{
READ,
READ_WRITE,
};
gl::ErrorOrResult<TextureHelper11> CreateStagingTexture(GLenum textureType,
const d3d11::Format &formatSet,
const gl::Extents &size,
StagingAccess readAndWriteAccess,
ID3D11Device *device);
bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachment *colorbuffer);
// Used for state change notifications between buffers and vertex arrays.
using OnBufferDataDirtyBinding = angle::ChannelBinding<size_t>;
using OnBufferDataDirtyChannel = angle::BroadcastChannel<size_t>;
using OnBufferDataDirtyReceiver = angle::SignalReceiver<size_t>;
// Used for state change notifications between RenderTarget11 and Framebuffer11.
using OnRenderTargetDirtyBinding = angle::ChannelBinding<size_t>;
using OnRenderTargetDirtyChannel = angle::BroadcastChannel<size_t>;
using OnRenderTargetDirtyReceiver = angle::SignalReceiver<size_t>;
} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_