You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/RenderDll/XRenderD3D9/DXGL/Implementation/GLResource.cpp

3974 lines
160 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Implements the resource related functions
#include "RenderDll_precompiled.h"
#include "GLResource.hpp"
#include "GLContext.hpp"
#include "GLDevice.hpp"
#include "GLView.hpp"
#define DXGL_USE_IMMUTABLE_TEXTURES !DXGL_SUPPORT_NSIGHT_SINCE(3_0)
#define DXGL_CHECK_TEXTURE_UPLOAD_READ_BOUNDS 0
#define DXGL_LOG_TEXTURE_SIZES 0
#define DXGL_SERVER_SIDE_SHARED_OBJECT_SYNCHRONIZATION 1
#define DXGL_PREVENT_NVIDIA_SUB_BUFFER_DATA_SYNCHRONIZATION 1
// NVidia NSight supports only OpenGL 4.2 API. The NamedFramebuffer functions are OpenGL 4.5
// and so captures fail when they are used. Change this define to 1 to enable the game to run
// with NSight and be able to get captures
#define USE_NVIDIA_NISGHT 0
namespace NCryOpenGL
{
enum
{
MIN_MAPPED_RESOURCE_ALIGNMENT = 64, // DX10+ mapped resources are 16-aligned but GL_ARB_map_buffer_alignment ensures 64-alignment for AVX
MAX_UNPACK_ALIGNMENT = 8,
MAX_PACK_ALIGNMENT = 8
};
uint32 GetRowPitch(uint32 uWidth, uint32 uRowBytes, const SGIFormatInfo* pFormatInfo)
{
uint32 uNumElementsPerRow(uRowBytes * pFormatInfo->m_pTexture->m_uBlockWidth / pFormatInfo->m_pTexture->m_uNumBlockBytes);
return uNumElementsPerRow == uWidth ? 0 : uNumElementsPerRow;
}
uint32 GetImagePitch(uint32 uHeight, uint32 uImageBytes, uint32 uRowBytes)
{
uint32 uNumRowsPerImage(uImageBytes / uRowBytes);
return uNumRowsPerImage == uHeight ? 0 : uNumRowsPerImage;
}
struct STexBox
{
STexPos m_kOffset;
STexSize m_kSize;
};
struct SPackedLayout
{
uint32 m_uRowPitch;
uint32 m_uImagePitch;
uint32 m_uTextureSize;
};
static GLint GetMaxMipLevels(const D3D11_TEXTURE1D_DESC& kTexDesc)
{
return (GLint)IntegerLog2(kTexDesc.Width);
}
static GLint GetMaxMipLevels(const D3D11_TEXTURE2D_DESC& kTexDesc)
{
return (GLint)max(IntegerLog2(kTexDesc.Width), IntegerLog2(kTexDesc.Height));
}
static GLint GetMaxMipLevels(const D3D11_TEXTURE3D_DESC& kTexDesc)
{
return (GLint)max(max(IntegerLog2(kTexDesc.Width), IntegerLog2(kTexDesc.Height)), IntegerLog2(kTexDesc.Depth));
}
template <typename TextureDesc>
static GLint GetNumMipLevels(const TextureDesc& kTexDesc)
{
return kTexDesc.MipLevels != 0 ? kTexDesc.MipLevels : GetMaxMipLevels(kTexDesc);
}
static STexSize GetMipSize(STexture* pTexture, GLint iLevel, const SGIFormatInfo* pFormat, bool bClampToBlockSize)
{
STexSize kMinSize(1, 1, 1);
if (bClampToBlockSize && pFormat->m_pTexture->m_bCompressed)
{
kMinSize = STexSize(
pFormat->m_pTexture->m_uBlockWidth,
pFormat->m_pTexture->m_uBlockHeight,
pFormat->m_pTexture->m_uBlockDepth);
}
return STexSize(
max(kMinSize.x, pTexture->m_iWidth >> iLevel),
max(kMinSize.y, pTexture->m_iHeight >> iLevel),
max(kMinSize.z, pTexture->m_iDepth >> iLevel));
}
void GetTextureBox(STexBox& kTexBox, STexture* pTexture, GLint iLevel, const SGIFormatInfo* pFormat, bool bClampToBlockSize)
{
kTexBox.m_kOffset = STexPos(0, 0, 0);
kTexBox.m_kSize = GetMipSize(pTexture, iLevel, pFormat, bClampToBlockSize);
}
void GetTextureBox(STexBox& kTexBox, STexture* pTexture, GLint iLevel, const D3D11_BOX* pBox, const SGIFormatInfo* pFormat, bool bClampToBlockSize)
{
if (pBox != NULL)
{
kTexBox.m_kOffset = STexPos(pBox->left, pBox->top, pBox->front);
kTexBox.m_kSize = STexSize(pBox->right - pBox->left, pBox->bottom - pBox->top, pBox->back - pBox->front);
}
else
{
GetTextureBox(kTexBox, pTexture, iLevel, pFormat, bClampToBlockSize);
}
}
SOutputMergerTextureViewPtr GetCopyOutputMergerView(STexture* pTexture, STexSubresourceID kSubID, CContext* pContext, const SGIFormatInfo* pFormatInfo)
{
uint32 uSubresource(D3D11CalcSubresource(kSubID.m_iMipLevel, kSubID.m_uElement, pTexture->m_uNumMipLevels));
DXGL_TODO("This is not thread-safe, as multiple threads can use the same texture as source/destination of copies. Add synchronization primitive.");
if (pTexture->m_kCopySubTextureViews.size() <= uSubresource)
{
pTexture->m_kCopySubTextureViews.resize(uSubresource + 1);
}
SOutputMergerTextureViewPtr spOMView(pTexture->m_kCopySubTextureViews.at(uSubresource));
if (spOMView == NULL)
{
spOMView = pTexture->GetCompatibleOutputMergerView(
SOutputMergerTextureViewConfiguration(pTexture->m_eFormat, kSubID.m_iMipLevel, kSubID.m_uElement, 1),
pContext);
pTexture->m_kCopySubTextureViews.at(uSubresource) = spOMView;
}
return spOMView;
}
struct STex1DBase
{
static GLsizei GetBCImageSize(STexSize kSize, const STextureFormat* pTexFormat)
{
return pTexFormat->m_uNumBlockBytes *
((kSize.x + pTexFormat->m_uBlockWidth - 1) / pTexFormat->m_uBlockWidth);
}
};
struct STex2DBase
{
static GLsizei GetBCImageSize(STexSize kSize, const STextureFormat* pTexFormat)
{
return pTexFormat->m_uNumBlockBytes *
((kSize.x + pTexFormat->m_uBlockWidth - 1) / pTexFormat->m_uBlockWidth) *
((kSize.y + pTexFormat->m_uBlockHeight - 1) / pTexFormat->m_uBlockHeight);
}
};
struct STex3DBase
{
static GLsizei GetBCImageSize(STexSize kSize, const STextureFormat* pTexFormat)
{
return pTexFormat->m_uNumBlockBytes *
((kSize.x + pTexFormat->m_uBlockWidth - 1) / pTexFormat->m_uBlockWidth) *
((kSize.y + pTexFormat->m_uBlockHeight - 1) / pTexFormat->m_uBlockHeight) *
((kSize.z + pTexFormat->m_uBlockDepth - 1) / pTexFormat->m_uBlockDepth);
}
};
struct SDefaultTexBase
{
static void AllocateResource(STexture* pTexture, CDevice* pDevice)
{
GLuint uName;
glGenTextures(1, &uName);
pTexture->m_kName = pDevice->GetTextureNamePool().Create(uName);
}
};
struct SDefaultTex1DBase
: SDefaultTexBase
, STex1DBase
{
static void TexStorage(STexture* pTexture, STexSize kSize, GLsizei iLevels, const STextureFormat* pTexFormat)
{
glTextureStorage1DEXT(pTexture->m_kName.GetName(), pTexture->m_eTarget, iLevels, pTexFormat->m_iInternalFormat, kSize.x);
}
static void ApplyUnpackState(CContext* pContext, STexSize kSize, uint32 uLogDataAlignment, uint32 uRowPitch, uint32, const SGIFormatInfo* pFormat)
{
pContext->SetUnpackAlignment(min((int)MAX_UNPACK_ALIGNMENT, 1 << uLogDataAlignment));
}
static void ApplyPackState(CContext* pContext, STexSize kSize, uint32 uLogDataAlignment, uint32 uRowPitch, uint32, const SGIFormatInfo* pFormat)
{
pContext->SetPackAlignment(min((int)MAX_PACK_ALIGNMENT, 1 << uLogDataAlignment));
}
};
struct SDefaultTex2DBase
: SDefaultTexBase
, STex2DBase
{
typedef SDefaultTex1DBase TArrayElement;
static void TexStorage(STexture* pTexture, STexSize kSize, GLsizei iLevels, const STextureFormat* pTexFormat)
{
glTextureStorage2DEXT(pTexture->m_kName.GetName(), pTexture->m_eTarget, iLevels, pTexFormat->m_iInternalFormat, kSize.x, kSize.y);
if ((pTexFormat->m_iInternalFormat == GL_DEPTH32F_STENCIL8) ||
(pTexFormat->m_iInternalFormat == GL_DEPTH_COMPONENT32F) ||
(pTexFormat->m_iInternalFormat == GL_DEPTH24_STENCIL8) ||
(pTexFormat->m_iInternalFormat == GL_DEPTH_COMPONENT16) ||
(pTexFormat->m_iInternalFormat == GL_R16UI) ||
(pTexFormat->m_iInternalFormat == GL_RG16UI) ||
(pTexFormat->m_iInternalFormat == GL_RGB10_A2UI))
{
glTextureParameteriEXT(pTexture->m_kName.GetName(), pTexture->m_eTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTextureParameteriEXT(pTexture->m_kName.GetName(), pTexture->m_eTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
}
static void ApplyUnpackState(CContext* pContext, STexSize kSize, uint32 uLogDataAlignment, uint32 uRowPitch, uint32, const SGIFormatInfo* pFormat)
{
pContext->SetUnpackRowLength(GetRowPitch(kSize.x, uRowPitch, pFormat));
pContext->SetUnpackAlignment(min((int)MAX_UNPACK_ALIGNMENT, 1 << min(uLogDataAlignment, (uint32)countTrailingZeroes(uRowPitch))));
}
static void ApplyPackState(CContext* pContext, STexSize kSize, uint32 uLogDataAlignment, uint32 uRowPitch, uint32, const SGIFormatInfo* pFormat)
{
pContext->SetPackRowLength(GetRowPitch(kSize.x, uRowPitch, pFormat));
pContext->SetPackAlignment(min((int)MAX_PACK_ALIGNMENT, 1 << min(uLogDataAlignment, (uint32)countTrailingZeroes(uRowPitch))));
}
template <typename T>
static void SetLayerComponent(STexVec<T>& kVec, T kLayer)
{
kVec.y = kLayer;
}
};
struct SDefaultTex3DBase
: SDefaultTexBase
, STex3DBase
{
typedef SDefaultTex2DBase TArrayElement;
static void TexStorage(STexture* pTexture, STexSize kSize, GLsizei iLevels, const STextureFormat* pTexFormat)
{
glTextureStorage3DEXT(pTexture->m_kName.GetName(), pTexture->m_eTarget, iLevels, pTexFormat->m_iInternalFormat, kSize.x, kSize.y, kSize.z);
}
static void ApplyUnpackState(CContext* pContext, STexSize kSize, uint32 uLogDataAlignment, uint32 uRowPitch, uint32 uImagePitch, const SGIFormatInfo* pFormat)
{
pContext->SetUnpackRowLength(GetRowPitch(kSize.x, uRowPitch, pFormat));
pContext->SetUnpackImageHeight(GetImagePitch(kSize.y, uImagePitch, uRowPitch));
pContext->SetUnpackAlignment(min((int)MAX_UNPACK_ALIGNMENT, 1 << min(uLogDataAlignment, (uint32)min(countTrailingZeroes(uRowPitch), countTrailingZeroes(uImagePitch)))));
}
static void ApplyPackState(CContext* pContext, STexSize kSize, uint32 uLogDataAlignment, uint32 uRowPitch, uint32 uImagePitch, const SGIFormatInfo* pFormat)
{
pContext->SetPackRowLength(GetRowPitch(kSize.x, uRowPitch, pFormat));
pContext->SetPackImageHeight(GetImagePitch(kSize.y, uImagePitch, uRowPitch));
pContext->SetPackAlignment(min((int)MAX_PACK_ALIGNMENT, 1 << min(uLogDataAlignment, (uint32)min(countTrailingZeroes(uRowPitch), countTrailingZeroes(uImagePitch)))));
}
template <typename T>
static void SetLayerComponent(STexVec<T>& kVec, T kLayer)
{
kVec.z = kLayer;
}
};
struct STexCompressed
{
#if DXGL_SUPPORT_GETTEXIMAGE
static void GetTexImage(STexture* pTexture, GLenum eTarget, GLint iLevel, GLvoid* pData, CContext*, const SGIFormatInfo*)
{
glGetCompressedTextureImageEXT(pTexture->m_kName.GetName(), eTarget, iLevel, pData);
}
#endif //DXGL_SUPPORT_GETTEXIMAGE
static bool GetPackedRange(const STexBox& kPixels, STexBox* pPackedRange, const SGIFormatInfo* pFormat)
{
const STextureFormat* pTexFormat(pFormat->m_pTexture);
if ((kPixels.m_kOffset.x % pTexFormat->m_uBlockWidth) != 0 ||
(kPixels.m_kOffset.y % pTexFormat->m_uBlockHeight) != 0 ||
(kPixels.m_kOffset.z % pTexFormat->m_uBlockDepth) != 0 ||
(kPixels.m_kSize.x % pTexFormat->m_uBlockWidth) != 0 ||
(kPixels.m_kSize.y % pTexFormat->m_uBlockHeight) != 0 ||
(kPixels.m_kSize.z % pTexFormat->m_uBlockDepth) != 0)
{
return false;
}
pPackedRange->m_kOffset.x = pTexFormat->m_uNumBlockBytes * kPixels.m_kOffset.x / pTexFormat->m_uBlockWidth;
pPackedRange->m_kSize.x = pTexFormat->m_uNumBlockBytes * kPixels.m_kSize.x / pTexFormat->m_uBlockWidth;
pPackedRange->m_kOffset.y = kPixels.m_kOffset.y / pTexFormat->m_uBlockHeight;
pPackedRange->m_kSize.y = kPixels.m_kSize.y / pTexFormat->m_uBlockHeight;
pPackedRange->m_kOffset.z = kPixels.m_kOffset.z / pTexFormat->m_uBlockDepth;
pPackedRange->m_kSize.z = kPixels.m_kSize.z / pTexFormat->m_uBlockDepth;
return true;
}
};
struct STexUncompressed
{
#if DXGL_SUPPORT_GETTEXIMAGE
static void GetTexImage(STexture* pTexture, GLenum eTarget, GLint iLevel, GLvoid* pData, CContext* pContext, const SGIFormatInfo* pFormatInfo)
{
glGetTextureImageEXT(pTexture->m_kName.GetName(), eTarget, iLevel, pFormatInfo->m_pTexture->m_eBaseFormat, pFormatInfo->m_pTexture->m_eDataType, pData);
}
#endif //DXGL_SUPPORT_GETTEXIMAGE
static bool GetPackedRange(const STexBox& kPixels, STexBox* pPackedRange, const SGIFormatInfo* pFormat)
{
uint32 uPixelBytes(pFormat->m_pTexture->m_uNumBlockBytes);
pPackedRange->m_kOffset.x = kPixels.m_kOffset.x * uPixelBytes;
pPackedRange->m_kSize.x = kPixels.m_kSize.x * uPixelBytes;
pPackedRange->m_kOffset.y = kPixels.m_kOffset.y;
pPackedRange->m_kSize.y = kPixels.m_kSize.y;
pPackedRange->m_kOffset.z = kPixels.m_kOffset.z;
pPackedRange->m_kSize.z = kPixels.m_kSize.z;
return true;
}
};
struct STex1DUncompressed
: SDefaultTex1DBase
, STexUncompressed
{
static void TexImage(STexture* pTexture, GLenum eTarget, GLint iLevel, STexSize kSize, GLint iBorder, const STextureFormat* pTexFormat, const GLvoid* pData)
{
glTextureImage1DEXT(pTexture->m_kName.GetName(), eTarget, iLevel, pTexFormat->m_iInternalFormat, kSize.x, iBorder, pTexFormat->m_eBaseFormat, pTexFormat->m_eDataType, pData);
}
static void TexSubImage(STexture* pTexture, GLenum eTarget, GLint iLevel, STexBox kBox, const STextureFormat* pTexFormat, const GLvoid* pData)
{
glTextureSubImage1DEXT(pTexture->m_kName.GetName(), eTarget, iLevel, kBox.m_kOffset.x, kBox.m_kSize.x, pTexFormat->m_eBaseFormat, pTexFormat->m_eDataType, pData);
}
static void GetPackedLayout(STexSize kRect, const SGIFormatInfo* pFormat, SPackedLayout* pLayout)
{
pLayout->m_uRowPitch = kRect.x * pFormat->m_pTexture->m_uNumBlockBytes;
pLayout->m_uImagePitch = pLayout->m_uRowPitch;
pLayout->m_uTextureSize = pLayout->m_uRowPitch;
}
};
struct STex2DUncompressed
: SDefaultTex2DBase
, STexUncompressed
{
static void TexImage(STexture* pTexture, GLenum eTarget, GLint iLevel, STexSize kSize, GLint iBorder, const STextureFormat* pTexFormat, const GLvoid* pData)
{
glTextureImage2DEXT(pTexture->m_kName.GetName(), eTarget, iLevel, pTexFormat->m_iInternalFormat, kSize.x, kSize.y, iBorder, pTexFormat->m_eBaseFormat, pTexFormat->m_eDataType, pData);
}
static void TexSubImage(STexture* pTexture, GLenum eTarget, GLint iLevel, STexBox kBox, const STextureFormat* pTexFormat, const GLvoid* pData)
{
glTextureSubImage2DEXT(pTexture->m_kName.GetName(), eTarget, iLevel, kBox.m_kOffset.x, kBox.m_kOffset.y, kBox.m_kSize.x, kBox.m_kSize.y, pTexFormat->m_eBaseFormat, pTexFormat->m_eDataType, pData);
}
static void GetPackedLayout(STexSize kRect, const SGIFormatInfo* pFormat, SPackedLayout* pLayout)
{
pLayout->m_uRowPitch = kRect.x * pFormat->m_pTexture->m_uNumBlockBytes;
pLayout->m_uImagePitch = kRect.y * pLayout->m_uRowPitch;
pLayout->m_uTextureSize = pLayout->m_uImagePitch;
}
};
struct STex3DUncompressed
: SDefaultTex3DBase
, STexUncompressed
{
static void TexImage(STexture* pTexture, GLenum eTarget, GLint iLevel, STexSize kSize, GLint iBorder, const STextureFormat* pTexFormat, const GLvoid* pData)
{
glTextureImage3DEXT(pTexture->m_kName.GetName(), eTarget, iLevel, pTexFormat->m_iInternalFormat, kSize.x, kSize.y, kSize.z, iBorder, pTexFormat->m_eBaseFormat, pTexFormat->m_eDataType, pData);
}
static void TexSubImage(STexture* pTexture, GLenum eTarget, GLint iLevel, STexBox kBox, const STextureFormat* pTexFormat, const GLvoid* pData)
{
glTextureSubImage3DEXT(pTexture->m_kName.GetName(), eTarget, iLevel, kBox.m_kOffset.x, kBox.m_kOffset.y, kBox.m_kOffset.z, kBox.m_kSize.x, kBox.m_kSize.y, kBox.m_kSize.z, pTexFormat->m_eBaseFormat, pTexFormat->m_eDataType, pData);
}
static void GetPackedLayout(STexSize kRect, const SGIFormatInfo* pFormat, SPackedLayout* pLayout)
{
pLayout->m_uRowPitch = kRect.x * pFormat->m_pTexture->m_uNumBlockBytes;
pLayout->m_uImagePitch = kRect.y * pLayout->m_uRowPitch;
pLayout->m_uTextureSize = kRect.z * pLayout->m_uImagePitch;
}
};
struct STex1DCompressed
: SDefaultTex1DBase
, STexCompressed
{
static void TexImage(STexture* pTexture, GLenum eTarget, GLint iLevel, STexSize kSize, GLint iBorder, const STextureFormat* pTexFormat, const GLvoid* pData)
{
glCompressedTextureImage1DEXT(pTexture->m_kName.GetName(), eTarget, iLevel, pTexFormat->m_iInternalFormat, kSize.x, iBorder, GetBCImageSize(kSize, pTexFormat), pData);
}
static void TexSubImage(STexture* pTexture, GLenum eTarget, GLint iLevel, STexBox kBox, const STextureFormat* pTexFormat, const GLvoid* pData)
{
// Note: According to the specification this takes the internal format and not the base format
DXGL_TODO("Verify the format parameter");
glCompressedTextureSubImage1DEXT(pTexture->m_kName.GetName(), eTarget, iLevel, kBox.m_kOffset.x, kBox.m_kSize.x, pTexFormat->m_iInternalFormat, GetBCImageSize(kBox.m_kSize, pTexFormat), pData);
}
static void GetPackedLayout(STexSize kRect, const SGIFormatInfo* pFormat, SPackedLayout* pLayout)
{
pLayout->m_uRowPitch = GetBCImageSize(kRect, pFormat->m_pTexture);
pLayout->m_uImagePitch = pLayout->m_uRowPitch;
pLayout->m_uTextureSize = pLayout->m_uRowPitch;
}
};
struct STex2DCompressed
: SDefaultTex2DBase
, STexCompressed
{
static void TexImage(STexture* pTexture, GLenum eTarget, GLint iLevel, STexSize kSize, GLint iBorder, const STextureFormat* pTexFormat, const GLvoid* pData)
{
glCompressedTextureImage2DEXT(pTexture->m_kName.GetName(), eTarget, iLevel, pTexFormat->m_iInternalFormat, kSize.x, kSize.y, iBorder, GetBCImageSize(kSize, pTexFormat), pData);
}
static void TexSubImage(STexture* pTexture, GLenum eTarget, GLint iLevel, STexBox kBox, const STextureFormat* pTexFormat, const GLvoid* pData)
{
// Note: According to the specification this takes the internal format and not the base format
DXGL_TODO("Verify the format parameter");
glCompressedTextureSubImage2DEXT(pTexture->m_kName.GetName(), eTarget, iLevel, kBox.m_kOffset.x, kBox.m_kOffset.y, kBox.m_kSize.x, kBox.m_kSize.y, pTexFormat->m_iInternalFormat, GetBCImageSize(kBox.m_kSize, pTexFormat), pData);
}
static void GetPackedLayout(STexSize kRect, const SGIFormatInfo* pFormat, SPackedLayout* pLayout)
{
pLayout->m_uRowPitch = GetBCImageSize(STexSize(kRect.x, 1, 1), pFormat->m_pTexture);
pLayout->m_uImagePitch = GetBCImageSize(kRect, pFormat->m_pTexture);
pLayout->m_uTextureSize = pLayout->m_uImagePitch;
}
};
struct STex3DCompressed
: SDefaultTex3DBase
, STexCompressed
{
static void TexImage(STexture* pTexture, GLenum eTarget, GLint iLevel, STexSize kSize, GLint iBorder, const STextureFormat* pTexFormat, const GLvoid* pData)
{
glCompressedTextureImage3DEXT(pTexture->m_kName.GetName(), eTarget, iLevel, pTexFormat->m_iInternalFormat, kSize.x, kSize.y, kSize.z, iBorder, GetBCImageSize(kSize, pTexFormat), pData);
}
static void TexSubImage(STexture* pTexture, GLenum eTarget, GLint iLevel, STexBox kBox, const STextureFormat* pTexFormat, const GLvoid* pData)
{
// Note: According to the specification this takes the internal format and not the base format
DXGL_TODO("Verify the format parameter");
glCompressedTextureSubImage3DEXT(pTexture->m_kName.GetName(), eTarget, iLevel, kBox.m_kOffset.x, kBox.m_kOffset.y, kBox.m_kOffset.z, kBox.m_kSize.x, kBox.m_kSize.y, kBox.m_kSize.z, pTexFormat->m_iInternalFormat, GetBCImageSize(kBox.m_kSize, pTexFormat), pData);
}
static void GetPackedLayout(STexSize kRect, const SGIFormatInfo* pFormat, SPackedLayout* pLayout)
{
pLayout->m_uRowPitch = GetBCImageSize(STexSize(kRect.x, 1, 1), pFormat->m_pTexture);
pLayout->m_uImagePitch = GetBCImageSize(STexSize(kRect.x, kRect.y, 1), pFormat->m_pTexture);
pLayout->m_uTextureSize = GetBCImageSize(kRect, pFormat->m_pTexture);
}
};
struct STexPartition
{
static void GetSubTargetAndLayer(STexture* pTexture, uint32 uElement, GLenum& eTarget, GLint& iLayer)
{
eTarget = pTexture->m_eTarget;
iLayer = (GLint)uElement;
}
static uint32 GetNumLayers(STexture* pTexture)
{
return pTexture->m_uNumElements;
}
static void InitializeCopyImageView(STexture* pTexture, const SGIFormatInfo* pFormat, CContext* pContext)
{
AZ_Assert(pContext->GetDevice()->IsFeatureSupported(eF_CopyImage), "Copy image is not supported on this platform");
pTexture->m_kCopyImageView = pTexture->m_kName;
pTexture->m_eCopyImageTarget = pTexture->m_eTarget;
}
};
struct SCubePartition
{
static void GetSubTargetAndLayer(STexture* pTexture, uint32 uElement, GLenum& eTarget, GLint& iLayer)
{
static const GLenum s_aeFaceTargets[] =
{
GL_TEXTURE_CUBE_MAP_POSITIVE_X, // 0
GL_TEXTURE_CUBE_MAP_NEGATIVE_X, // 1
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, // 2
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, // 3
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, // 4
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z // 5
};
eTarget = s_aeFaceTargets[uElement % 6];
iLayer = uElement / 6;
}
static uint32 GetNumLayers(STexture* pTexture)
{
return pTexture->m_uNumElements / 6;
}
static void InitializeCopyImageView(STexture* pTexture, const SGIFormatInfo* pFormat, CContext* pContext)
{
CDevice* pDevice(pContext->GetDevice());
AZ_Assert(pDevice->IsFeatureSupported(eF_CopyImage), "Copy image is not supported on this platform");
if (!pDevice->GetAdapter()->m_kCapabilities.m_bCopyImageWorksOnCubeMapFaces && pDevice->IsFeatureSupported(eF_TextureViews))
{
GLuint uCopyViewName;
glGenTextures(1, &uCopyViewName);
glTextureViewEXT(uCopyViewName, GL_TEXTURE_2D_ARRAY, pTexture->m_kName.GetName(), pFormat->m_pTexture->m_iInternalFormat, 0, pTexture->m_uNumMipLevels, 0, pTexture->m_uNumElements);
pTexture->m_kCopyImageView = pDevice->GetTextureNamePool().Create(uCopyViewName);
pTexture->m_eCopyImageTarget = GL_TEXTURE_2D_ARRAY;
}
else
{
pTexture->m_kCopyImageView = pTexture->m_kName;
pTexture->m_eCopyImageTarget = pTexture->m_eTarget;
}
}
};
#if DXGL_CHECK_TEXTURE_UPLOAD_READ_BOUNDS
uint32 GetPageSize()
{
#if defined(WIN32)
SYSTEM_INFO kInfo;
::GetSystemInfo(&kInfo);
return kInfo.dwPageSize;
#else
return getpagesize();
#endif
}
template <typename Interface>
void TestUploadBounds(STexture* pTexture, GLenum eTarget, GLint iLevel, STexBox kBox, const SGIFormatInfo* pFormat, const GLvoid* pData, uint32 uSrcRowPitch, uint32 uSrcDepthPitch)
{
static uint32 s_uPageSize = GetPageSize();
static std::map<uint32, char*> s_kBuffers;
static uint32 s_uNumBufferPages = 0;
uint32 uSize;
if (pFormat->m_pTexture->m_bCompressed)
{
uSize = Interface::GetBCImageSize(kBox.m_kSize, pFormat->m_pTexture);
}
else if (kBox.m_kSize.z > 1)
{
uSize = kBox.m_kSize.z * uSrcDepthPitch;
}
else if (kBox.m_kSize.y > 1)
{
uSize = kBox.m_kSize.y * uSrcRowPitch;
}
else
{
uSize = kBox.m_kSize.x * pFormat->m_pTexture->m_uNumBlockBytes;
}
uint32 uRequiredPages(2 + (uSize + s_uPageSize) / s_uPageSize);
char* pBuffer;
std::map<uint32, char*>::iterator kFound(s_kBuffers.find(uRequiredPages));
if (kFound != s_kBuffers.end())
{
pBuffer = kFound->second;
}
else
{
#if defined(WIN32)
pBuffer = reinterpret_cast<char*>(VirtualAlloc(NULL, uRequiredPages * s_uPageSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
DWORD uUnused;
VirtualProtect(pBuffer, s_uPageSize, PAGE_NOACCESS, &uUnused);
VirtualProtect(pBuffer + s_uPageSize * (uRequiredPages - 1), s_uPageSize, PAGE_NOACCESS, &uUnused);
#else
pBuffer = reinterpret_cast<char*>(mmap(NULL, uRequiredPages * s_uPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0));
mprotect(pBuffer, s_uPageSize, PROT_NONE);
mprotect(pBuffer + s_uPageSize * (uRequiredPages - 1), s_uPageSize, PROT_NONE);
#endif
}
Interface::TexSubImage(pTexture, eTarget, iLevel, kBox, pFormat->m_pTexture, pBuffer + s_uPageSize);
Interface::TexSubImage(pTexture, eTarget, iLevel, kBox, pFormat->m_pTexture, pBuffer + (uRequiredPages - 1) * s_uPageSize - uSize);
}
#else
template <typename Interface>
void TestUploadBounds(STexture*, GLenum, GLint, STexBox, const SGIFormatInfo*, const GLvoid*, uint32, uint32){}
#endif
template <typename Interface, typename Partition>
void LogTextureSize(STexture* pTexture)
{
#if DXGL_LOG_TEXTURE_SIZES
const char* szFormatName = "(invalid)";
switch (pTexture->m_eFormat)
{
#define _GI_FORMAT_ENUM_FUNC(_FormatID, ...) case DXGL_GI_FORMAT(_FormatID): \
szFormatName = DXGL_QUOTE(_FormatID); break;
DXGL_GI_FORMATS(_GI_FORMAT_ENUM_FUNC)
#undef _GI_FORMAT_ENUM_FUNC
}
GLint iLayer;
GLenum eTarget;
Partition::GetSubTargetAndLayer(pTexture, 0, eTarget, iLayer);
uint32 uLevel;
for (uLevel = 0; uLevel < pTexture->m_uNumMipLevels; ++uLevel)
{
GLint iWidth, iHeight, iDepth;
glGetTextureLevelParameterivEXT(pTexture->m_kName.GetName(), eTarget, uLevel, GL_TEXTURE_WIDTH, &iWidth);
glGetTextureLevelParameterivEXT(pTexture->m_kName.GetName(), eTarget, uLevel, GL_TEXTURE_HEIGHT, &iHeight);
glGetTextureLevelParameterivEXT(pTexture->m_kName.GetName(), eTarget, uLevel, GL_TEXTURE_DEPTH, &iDepth);
CryLogAlways(" TEXTURE SIZE name=%d format=%s level=%d size=[%d, %d, %d]\n", pTexture->m_kName.GetName(), szFormatName, uLevel, iWidth, iHeight, iDepth);
}
#endif
}
template <typename Interface, typename Partition = STexPartition>
struct SSingleTexImpl
: Interface
{
static void InitializeStorage(STexture* pTexture, uint32, const SGIFormatInfo* pFormat, CContext* pContext)
{
#if DXGL_USE_IMMUTABLE_TEXTURES
Interface::TexStorage(pTexture, GetMipSize(pTexture, 0, pFormat, false), pTexture->m_uNumMipLevels, pFormat->m_pTexture);
#else
GLint iLevel;
uint32 uElement;
for (uElement = 0; uElement < pTexture->m_uNumElements; ++uElement)
{
GLenum eSubTarget;
GLint iLayer;
Partition::GetSubTargetAndLayer(pTexture, uElement, eSubTarget, iLayer);
assert(iLayer == 0);
for (iLevel = 0; iLevel < (GLint)pTexture->m_uNumMipLevels; ++iLevel)
{
Interface::TexImage(pTexture, eSubTarget, iLevel, GetMipSize(pTexture, iLevel, pFormat, false), 0, pFormat->m_pTexture, NULL);
}
}
#endif
if (pContext->GetDevice()->IsFeatureSupported(eF_CopyImage))
{
Partition::InitializeCopyImageView(pTexture, pFormat, pContext);
}
LogTextureSize<Interface, Partition>(pTexture);
}
static void UploadImage(STexture* pTexture, STexSubresourceID kSubID, STexBox kBox, const void* pSrcData, uint32 uSrcRowPitch, uint32 uSrcDepthPitch, CContext* pContext, const SGIFormatInfo* pFormat)
{
GLenum eSubTarget;
GLint iLayer;
Partition::GetSubTargetAndLayer(pTexture, kSubID.m_uElement, eSubTarget, iLayer);
assert(iLayer == 0);
Interface::ApplyUnpackState(pContext, kBox.m_kSize, (uint32)countTrailingZeroes((unsigned int)reinterpret_cast<uintptr_t>(pSrcData)), uSrcRowPitch, uSrcDepthPitch, pFormat);
TestUploadBounds<Interface>(pTexture, eSubTarget, kSubID.m_iMipLevel, kBox, pFormat, pSrcData, uSrcRowPitch, uSrcDepthPitch);
Interface::TexSubImage(pTexture, eSubTarget, kSubID.m_iMipLevel, kBox, pFormat->m_pTexture, pSrcData);
}
static void DownloadImage(STexture* pTexture, STexSubresourceID kSubID, STexBox kBox, void* pDstData, uint32 uDstRowPitch, uint32 uDstDepthPitch, CContext* pContext, const SGIFormatInfo* pFormat)
{
Interface::ApplyPackState(pContext, kBox.m_kSize, (uint32)countTrailingZeroes((unsigned int)reinterpret_cast<uintptr_t>(pDstData)), uDstRowPitch, uDstDepthPitch, pFormat);
#if DXGL_SUPPORT_GETTEXIMAGE
GLenum eSubTarget;
GLint iLayer;
Partition::GetSubTargetAndLayer(pTexture, kSubID.m_uElement, eSubTarget, iLayer);
assert(iLayer == 0);
Interface::GetTexImage(pTexture, eSubTarget, kSubID.m_iMipLevel, pDstData, pContext, pFormat);
#else
if (kBox.m_kOffset.z > 0 || kBox.m_kSize.z > 1)
{
DXGL_NOT_IMPLEMENTED
}
SOutputMergerTextureViewPtr spView(GetCopyOutputMergerView(pTexture, kSubID, pContext, pFormat));
if (spView == NULL)
{
DXGL_ERROR("Could not create an output merger view for texture readback");
return;
}
if (!pContext->ReadBackOutputMergerView(spView, kBox.m_kOffset.x, kBox.m_kOffset.y, kBox.m_kSize.x, kBox.m_kSize.y, pDstData))
{
DXGL_ERROR("Texture readback failed");
return;
}
#endif
}
static void Map(STexture* pTexture, STexSubresourceID kSubID, bool bDownload, SMappedSubTexture& kMappedSubTex, CContext* pContext, const SGIFormatInfo* pFormat)
{
STexBox kBox;
GetTextureBox(kBox, pTexture, kSubID.m_iMipLevel, pFormat, true);
SPackedLayout kPackedLayout;
Interface::GetPackedLayout(kBox.m_kSize, pFormat, &kPackedLayout);
DXGL_TODO("Check if it's worth to keep an allocation pool");
kMappedSubTex.m_pBuffer = static_cast<uint8*>(Memalign(kPackedLayout.m_uTextureSize, MIN_MAPPED_RESOURCE_ALIGNMENT));
kMappedSubTex.m_uRowPitch = kPackedLayout.m_uRowPitch;
kMappedSubTex.m_uImagePitch = kPackedLayout.m_uImagePitch;
kMappedSubTex.m_uDataOffset = 0;
if (bDownload)
{
DownloadImage(pTexture, kSubID, kBox, kMappedSubTex.m_pBuffer, kPackedLayout.m_uRowPitch, kPackedLayout.m_uImagePitch, pContext, pFormat);
}
}
static void Unmap(STexture* pTexture, STexSubresourceID kSubID, const SMappedSubTexture& kMappedSubTex, CContext* pContext, const SGIFormatInfo* pFormat)
{
if (kMappedSubTex.m_bUpload)
{
STexBox kBox;
GetTextureBox(kBox, pTexture, kSubID.m_iMipLevel, pFormat, true);
UploadImage(pTexture, kSubID, kBox, kMappedSubTex.m_pBuffer, kMappedSubTex.m_uRowPitch, kMappedSubTex.m_uImagePitch, pContext, pFormat);
}
MemalignFree(kMappedSubTex.m_pBuffer);
}
};
template <typename Interface, typename Partition = STexPartition>
struct SArrayTexImpl
: Interface
{
static void InitializeStorage(STexture* pTexture, uint32, const SGIFormatInfo* pFormat, CContext* pContext)
{
#if DXGL_USE_IMMUTABLE_TEXTURES
STexSize kTexSize(GetMipSize(pTexture, 0, pFormat, false));
Interface::SetLayerComponent(kTexSize, (GLsizei)pTexture->m_uNumElements);
Interface::TexStorage(pTexture, kTexSize, pTexture->m_uNumMipLevels, pFormat->m_pTexture);
#else
GLint iLevel;
for (iLevel = 0; iLevel < (GLint)pTexture->m_uNumMipLevels; ++iLevel)
{
STexSize kMipSize(GetMipSize(pTexture, iLevel, pFormat, false));
Interface::SetLayerComponent(kMipSize, (GLsizei)pTexture->m_uNumElements);
Interface::TexImage(pTexture, pTexture->m_eTarget, iLevel, kMipSize, 0, pFormat->m_pTexture, NULL);
}
#endif
if (pContext->GetDevice()->IsFeatureSupported(eF_CopyImage))
{
Partition::InitializeCopyImageView(pTexture, pFormat, pContext);
}
LogTextureSize<Interface, Partition>(pTexture);
}
static void UploadImage(STexture* pTexture, STexSubresourceID kSubID, STexBox kBox, const void* pSrcData, uint32 uSrcRowPitch, uint32 uSrcDepthPitch, CContext* pContext, const SGIFormatInfo* pFormat)
{
GLenum eSubTarget;
GLint iLayer;
Partition::GetSubTargetAndLayer(pTexture, kSubID.m_uElement, eSubTarget, iLayer);
Interface::SetLayerComponent(kBox.m_kOffset, iLayer);
Interface::SetLayerComponent(kBox.m_kSize, 1);
Interface::ApplyUnpackState(pContext, kBox.m_kSize, (uint32)countTrailingZeroes((unsigned int)reinterpret_cast<uintptr_t>(pSrcData)), uSrcRowPitch, uSrcDepthPitch, pFormat);
TestUploadBounds<Interface>(pTexture, eSubTarget, kSubID.m_iMipLevel, kBox, pFormat, pSrcData, uSrcRowPitch, uSrcDepthPitch);
Interface::TexSubImage(pTexture, eSubTarget, kSubID.m_iMipLevel, kBox, pFormat->m_pTexture, pSrcData);
}
static void DownloadImage(STexture* pTexture, STexSubresourceID kSubID, STexBox kBox, void* pDstData, uint32 uDstRowPitch, uint32 uDstDepthPitch, CContext* pContext, const SGIFormatInfo* pFormat)
{
Interface::ApplyPackState(pContext, kBox.m_kSize, (uint32)countTrailingZeroes((unsigned int)reinterpret_cast<uintptr_t>(pDstData)), uDstRowPitch, uDstDepthPitch, pFormat);
#if DXGL_SUPPORT_GETTEXIMAGE
GLenum eSubTarget;
GLint iLayer;
Partition::GetSubTargetAndLayer(pTexture, kSubID.m_uElement, eSubTarget, iLayer);
Interface::GetTexImage(pTexture, eSubTarget, kSubID.m_iMipLevel, pDstData, pContext, pFormat);
#else
DXGL_NOT_IMPLEMENTED
#endif
}
static void Map(STexture* pTexture, STexSubresourceID kSubID, bool bDownload, SMappedSubTexture& kMappedSubTex, CContext* pContext, const SGIFormatInfo* pFormat)
{
GLenum eSubTarget;
GLint iLayer;
Partition::GetSubTargetAndLayer(pTexture, kSubID.m_uElement, eSubTarget, iLayer);
STexBox kBox;
GetTextureBox(kBox, pTexture, kSubID.m_iMipLevel, pFormat, true);
uint32 uNumTextures(1);
uint32 uTextureIndex(0);
if (bDownload)
{
// The box must include all layers since glGetTexImage can only copy all layers at once.
// This is quite a waste, but as of 4.3 there's no way to only download a single layer
// (excluding glReadPixels that only works for renderable formats, i.e. not compressed formats).
Interface::SetLayerComponent(kBox.m_kSize, (GLsizei)Partition::GetNumLayers(pTexture));
}
SPackedLayout kPackedLayout;
Interface::GetPackedLayout(kBox.m_kSize, pFormat, &kPackedLayout);
DXGL_TODO("Check if it's worth to keep an allocation pool");
kMappedSubTex.m_pBuffer = static_cast<uint8*>(Memalign(kPackedLayout.m_uTextureSize, MIN_MAPPED_RESOURCE_ALIGNMENT));
kMappedSubTex.m_uRowPitch = kPackedLayout.m_uRowPitch;
kMappedSubTex.m_uImagePitch = kPackedLayout.m_uImagePitch;
kMappedSubTex.m_uDataOffset = 0;
if (bDownload)
{
kMappedSubTex.m_uDataOffset = iLayer * kPackedLayout.m_uImagePitch;
DownloadImage(pTexture, kSubID, kBox, kMappedSubTex.m_pBuffer, kPackedLayout.m_uRowPitch, kPackedLayout.m_uImagePitch, pContext, pFormat);
}
}
static void Unmap(STexture* pTexture, STexSubresourceID kSubID, const SMappedSubTexture& kMappedSubTex, CContext* pContext, const SGIFormatInfo* pFormat)
{
if (kMappedSubTex.m_bUpload)
{
GLenum eSubTarget;
GLint iLayer;
Partition::GetSubTargetAndLayer(pTexture, kSubID.m_uElement, eSubTarget, iLayer);
STexBox kBox;
GetTextureBox(kBox, pTexture, kSubID.m_iMipLevel, pFormat, true);
GLvoid* pData(kMappedSubTex.m_pBuffer + kMappedSubTex.m_uDataOffset);
UploadImage(pTexture, kSubID, kBox, pData, kMappedSubTex.m_uRowPitch, kMappedSubTex.m_uImagePitch, pContext, pFormat);
}
MemalignFree(kMappedSubTex.m_pBuffer);
}
};
template <typename Interface>
uint32 GetSystemMemoryTextureOffset(STexture* pTexture, const SGIFormatInfo* pFormat, STexSubresourceID kID)
{
uint32 uOffset(0);
uint32 uTotSize(0);
uint32 uLevel;
for (uLevel = 0; uLevel < pTexture->m_uNumMipLevels; ++uLevel)
{
STexSize kLevelSize(GetMipSize(pTexture, (GLint)uLevel, pFormat, true));
SPackedLayout kPackedLayout;
Interface::GetPackedLayout(kLevelSize, pFormat, &kPackedLayout);
uTotSize += kPackedLayout.m_uTextureSize;
// Keep every subresource aligned so that it can be directly mapped
uTotSize += MIN_MAPPED_RESOURCE_ALIGNMENT - 1;
uTotSize -= (uTotSize % MIN_MAPPED_RESOURCE_ALIGNMENT);
if (uLevel < kID.m_iMipLevel)
{
uOffset = uTotSize;
}
}
return uTotSize * kID.m_uElement + uOffset;
}
template <typename Interface>
struct SStagingTexImpl
: Interface
{
static void AllocateResource(STexture* pTexture, CDevice* pDevice)
{
#if DXGL_USE_PBO_FOR_STAGING_TEXTURES
uint32 uNumPixelBuffers(pTexture->m_uNumMipLevels * pTexture->m_uNumElements);
pTexture->m_akPixelBuffers = new CResourceName[uNumPixelBuffers];
for (uint32 uPixelBuffer = 0; uPixelBuffer < uNumPixelBuffers; ++uPixelBuffer)
{
GLuint uPixelBufferName;
glGenBuffers(1, &uPixelBufferName);
pTexture->m_akPixelBuffers[uPixelBuffer] = pDevice->GetBufferNamePool().Create(uPixelBufferName);
}
#endif //DXGL_USE_PBO_FOR_STAGING_TEXTURES
}
static void InitializeStorage(STexture* pTexture, uint32 uCPUAccess, const SGIFormatInfo* pFormat, CContext* pContext)
{
#if DXGL_USE_PBO_FOR_STAGING_TEXTURES
GLenum eUsage;
if ((uCPUAccess & D3D11_CPU_ACCESS_WRITE) == 0)
{
eUsage = GL_STREAM_READ;
}
else if ((uCPUAccess & D3D11_CPU_ACCESS_READ) == 0)
{
eUsage = GL_STREAM_DRAW;
}
else
{
eUsage = GL_STREAM_COPY;
}
STexSubresourceID kSubID;
for (kSubID.m_iMipLevel = 0; kSubID.m_iMipLevel < pTexture->m_uNumMipLevels; ++kSubID.m_iMipLevel)
{
STexSize kLevelSize(GetMipSize(pTexture, kSubID.m_iMipLevel, pFormat, true));
SPackedLayout kPackedLayout;
Interface::GetPackedLayout(kLevelSize, pFormat, &kPackedLayout);
for (kSubID.m_uElement = 0; kSubID.m_uElement < pTexture->m_uNumElements; ++kSubID.m_uElement)
{
uint32 uSubResource(D3D11CalcSubresource(kSubID.m_iMipLevel, kSubID.m_uElement, pTexture->m_uNumMipLevels));
glNamedBufferDataEXT(pTexture->m_akPixelBuffers[uSubResource].GetName(), kPackedLayout.m_uTextureSize, NULL, eUsage);
}
}
#else
STexSubresourceID kEndID = {pTexture->m_uNumMipLevels, pTexture->m_uNumElements};
uint32 uMappedSize(GetSystemMemoryTextureOffset<Interface>(pTexture, pFormat, kEndID));
pTexture->m_pSystemMemoryCopy = static_cast<uint8*>(Memalign(uMappedSize, MIN_MAPPED_RESOURCE_ALIGNMENT));
#endif
}
static void UploadImage(STexture* pTexture, STexSubresourceID kSubID, STexBox kBox, const void* pSrcData, uint32 uSrcRowPitch, uint32 uSrcDepthPitch, CContext* pContext, const SGIFormatInfo* pFormat)
{
STexSize kDstSize(GetMipSize(pTexture, kSubID.m_iMipLevel, pFormat, true));
SPackedLayout kDstLayout;
Interface::GetPackedLayout(kDstSize, pFormat, &kDstLayout);
STexBox kPackedRange;
if (!Interface::GetPackedRange(kBox, &kPackedRange, pFormat))
{
DXGL_ERROR("Texture upload box is not compatible with the format of the texture");
return;
}
#if DXGL_USE_PBO_FOR_STAGING_TEXTURES
uint32 uSubResource(D3D11CalcSubresource(kSubID.m_iMipLevel, kSubID.m_uElement, pTexture->m_uNumMipLevels));
GLvoid* pvMappedData(pContext->MapNamedBufferRangeFast(pTexture->m_akPixelBuffers[uSubResource], 0, (GLsizei)kDstLayout.m_uTextureSize, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT));
uint8* puDstData(static_cast<uint8*>(pvMappedData) + kPackedRange.m_kOffset.x);
#else
uint8* puDstData(
pTexture->m_pSystemMemoryCopy +
GetSystemMemoryTextureOffset<Interface>(pTexture, pFormat, kSubID) +
kPackedRange.m_kOffset.x);
#endif
const uint8* puSrcData(reinterpret_cast<const uint8*>(pSrcData));
uint32 uImage, uRow;
for (uImage = kPackedRange.m_kOffset.z; uImage < kPackedRange.m_kSize.z; ++uImage)
{
for (uRow = kPackedRange.m_kOffset.y; uRow < kPackedRange.m_kSize.y; ++uRow)
{
cryMemcpy(
puDstData + uImage * kDstLayout.m_uImagePitch + uRow * kDstLayout.m_uRowPitch + kPackedRange.m_kOffset.x,
puSrcData + uImage * uSrcDepthPitch + uRow * uSrcRowPitch,
kPackedRange.m_kSize.x);
}
}
#if DXGL_USE_PBO_FOR_STAGING_TEXTURES
pContext->UnmapNamedBufferFast(pTexture->m_akPixelBuffers[uSubResource]);
#endif //DXGL_USE_PBO_FOR_STAGING_TEXTURES
}
#if DXGL_USE_PBO_FOR_STAGING_TEXTURES
static void DownloadImage(STexture* pTexture, STexSubresourceID kSubID, STexBox kBox, const void* pDstData, uint32 uSrcRowPitch, uint32 uSrcDepthPitch, CContext* pContext, const SGIFormatInfo* pFormat)
{
DXGL_NOT_IMPLEMENTED
}
#endif //DXGL_USE_PBO_FOR_STAGING_TEXTURES
static void Map(STexture* pTexture, STexSubresourceID kSubID, bool bDownload, SMappedSubTexture& kMappedSubTex, CContext* pContext, const SGIFormatInfo* pFormat)
{
STexSize kSubSize(GetMipSize(pTexture, kSubID.m_iMipLevel, pFormat, true));
SPackedLayout kPackedLayout;
Interface::GetPackedLayout(kSubSize, pFormat, &kPackedLayout);
#if DXGL_USE_PBO_FOR_STAGING_TEXTURES
uint32 uSubResource(D3D11CalcSubresource(kSubID.m_iMipLevel, kSubID.m_uElement, pTexture->m_uNumMipLevels));
GLint iPixelBufferName(pTexture->m_akPixelBuffers[uSubResource].GetName());
if (bDownload)
{
kMappedSubTex.m_pBuffer = static_cast<uint8*>(pContext->MapNamedBufferRangeFast(pTexture->m_akPixelBuffers[uSubResource], 0, kPackedLayout.m_uTextureSize, GL_MAP_READ_BIT));
}
else
{
kMappedSubTex.m_pBuffer = static_cast<uint8*>(pContext->MapNamedBufferRangeFast(pTexture->m_akPixelBuffers[uSubResource], 0, kPackedLayout.m_uTextureSize, GL_MAP_WRITE_BIT));
}
#else
kMappedSubTex.m_pBuffer = pTexture->m_pSystemMemoryCopy + GetSystemMemoryTextureOffset<Interface>(pTexture, pFormat, kSubID);
#endif
kMappedSubTex.m_uRowPitch = kPackedLayout.m_uRowPitch;
kMappedSubTex.m_uImagePitch = kPackedLayout.m_uImagePitch;
kMappedSubTex.m_uDataOffset = 0;
}
static void Unmap(STexture* pTexture, STexSubresourceID kSubID, const SMappedSubTexture& kMappedSubTex, CContext* pContext, const SGIFormatInfo*)
{
#if DXGL_USE_PBO_FOR_STAGING_TEXTURES
uint32 uSubResource(D3D11CalcSubresource(kSubID.m_iMipLevel, kSubID.m_uElement, pTexture->m_uNumMipLevels));
pContext->UnmapNamedBufferFast(pTexture->m_akPixelBuffers[uSubResource]);
#endif //DXGL_USE_PBO_FOR_STAGING_TEXTURES
}
};
inline STexSubresourceID GetTexSubresourceID(STexture* pTexture, uint32 uSubresource)
{
STexSubresourceID kID;
kID.m_iMipLevel = uSubresource % pTexture->m_uNumMipLevels;
kID.m_uElement = uSubresource / pTexture->m_uNumMipLevels;
assert(kID.m_uElement < pTexture->m_uNumElements);
return kID;
}
template <typename Impl>
void UpdateTexSubresource(SResource* pResource, uint32 uSubresource, const D3D11_BOX* pDstBox, const void* pSrcData, uint32 uSrcRowPitch, uint32 uSrcDepthPitch, CContext* pContext)
{
DXGL_SCOPED_PROFILE("UpdateTexSubresource")
STexture * pTexture(static_cast<STexture*>(pResource));
pTexture->m_kCreationFence.IssueWait(pContext);
const SGIFormatInfo* pFormatInfo(GetGIFormatInfo(pTexture->m_eFormat));
assert(pFormatInfo != NULL);
assert(pFormatInfo->m_pTexture != NULL);
STexSubresourceID kSubID(GetTexSubresourceID(pTexture, uSubresource));
STexBox kTexBox;
GetTextureBox(kTexBox, pTexture, kSubID.m_iMipLevel, pDstBox, pFormatInfo, false);
Impl::UploadImage(pTexture, kSubID, kTexBox, pSrcData, uSrcRowPitch, uSrcDepthPitch, pContext, pFormatInfo);
}
template <typename Impl>
bool MapTexSubresource(SResource* pResource, uint32 uSubresource, D3D11_MAP eMapType, uint32 uMapFlags, D3D11_MAPPED_SUBRESOURCE* pMappedResource, CContext* pContext)
{
DXGL_SCOPED_PROFILE("MapTexSubresource")
STexture * pTexture(static_cast<STexture*>(pResource));
pTexture->m_kCreationFence.IssueWait(pContext);
const SGIFormatInfo* pFormatInfo(GetGIFormatInfo(pTexture->m_eFormat));
assert(pFormatInfo != NULL);
assert(pFormatInfo->m_pTexture != NULL);
if (uSubresource >= pTexture->m_kMappedSubTextures.size())
{
pTexture->m_kMappedSubTextures.resize(uSubresource + 1);
}
SMappedSubTexture& kMappedSubTexture(pTexture->m_kMappedSubTextures.at(uSubresource));
if (kMappedSubTexture.m_pBuffer != NULL)
{
DXGL_ERROR("Texture subresource is already mapped");
return false;
}
bool bDownload(eMapType == D3D11_MAP_READ || eMapType == D3D11_MAP_WRITE || eMapType == D3D11_MAP_READ_WRITE);
Impl::Map(pTexture, GetTexSubresourceID(pTexture, uSubresource), bDownload, kMappedSubTexture, pContext, pFormatInfo);
kMappedSubTexture.m_bUpload = (eMapType != D3D11_MAP_READ);
pMappedResource->pData = kMappedSubTexture.m_pBuffer + kMappedSubTexture.m_uDataOffset;
pMappedResource->RowPitch = kMappedSubTexture.m_uRowPitch;
pMappedResource->DepthPitch = kMappedSubTexture.m_uImagePitch;
return kMappedSubTexture.m_pBuffer != NULL;
}
template <typename Impl>
void UnmapTexSubresource(SResource* pResource, UINT uSubresource, CContext* pContext)
{
DXGL_SCOPED_PROFILE("UnmapTexSubresource")
STexture * pTexture(static_cast<STexture*>(pResource));
const SGIFormatInfo* pFormatInfo(GetGIFormatInfo(pTexture->m_eFormat));
assert(pFormatInfo != NULL);
assert(pFormatInfo->m_pTexture != NULL);
if (uSubresource >= pTexture->m_kMappedSubTextures.size())
{
pTexture->m_kMappedSubTextures.resize(uSubresource + 1);
}
SMappedSubTexture& kMappedSubTexture(pTexture->m_kMappedSubTextures.at(uSubresource));
if (kMappedSubTexture.m_pBuffer == NULL)
{
DXGL_ERROR("Texture subresource is not mapped");
return;
}
Impl::Unmap(pTexture, GetTexSubresourceID(pTexture, uSubresource), kMappedSubTexture, pContext, pFormatInfo);
kMappedSubTexture.m_pBuffer = NULL;
}
template <typename Impl>
void UnpackTexData(STexture* pTexture, STexSubresourceID kSubID, STexPos kOffset, STexSize kSize, const SMappedSubTexture& kDataLocation, CContext* pContext)
{
DXGL_SCOPED_PROFILE("UnpackTexData")
STexBox kBox;
kBox.m_kOffset = kOffset;
kBox.m_kSize = kSize;
const SGIFormatInfo* pFormat(GetGIFormatInfo(pTexture->m_eFormat));
Impl::UploadImage(pTexture, kSubID, kBox, kDataLocation.m_pBuffer + kDataLocation.m_uDataOffset, kDataLocation.m_uRowPitch, kDataLocation.m_uImagePitch, pContext, pFormat);
}
template <typename Impl>
void PackTexData(STexture* pTexture, STexSubresourceID kSubID, STexPos kOffset, STexSize kSize, const SMappedSubTexture& kDataLocation, CContext* pContext)
{
DXGL_SCOPED_PROFILE("PackTexData")
STexBox kBox;
kBox.m_kOffset = kOffset;
kBox.m_kSize = kSize;
const SGIFormatInfo* pFormat(GetGIFormatInfo(pTexture->m_eFormat));
Impl::DownloadImage(pTexture, kSubID, kBox, kDataLocation.m_pBuffer + kDataLocation.m_uDataOffset, kDataLocation.m_uRowPitch, kDataLocation.m_uImagePitch, pContext, pFormat);
}
template <typename Impl>
uint32 LocateTexPackedData(STexture* pTexture, STexSubresourceID kSubID, STexPos kOffset, SMappedSubTexture& kDataLocation)
{
const SGIFormatInfo* pFormat(GetGIFormatInfo(pTexture->m_eFormat));
STexBox kBox;
GetTextureBox(kBox, pTexture, kSubID.m_iMipLevel, pFormat, true);
SPackedLayout kPackedLayout;
Impl::GetPackedLayout(kBox.m_kSize, pFormat, &kPackedLayout);
SPackedLayout kPackedOffset;
Impl::GetPackedLayout(STexSize((GLsizei)kOffset.x, (GLsizei)kOffset.y, (GLsizei)kOffset.z), pFormat, &kPackedOffset);
kDataLocation.m_pBuffer = NULL;
kDataLocation.m_uDataOffset = kPackedOffset.m_uTextureSize;
kDataLocation.m_uRowPitch = kPackedLayout.m_uRowPitch;
kDataLocation.m_uImagePitch = kPackedLayout.m_uImagePitch;
return kPackedLayout.m_uTextureSize;
}
template <typename Impl>
void InitializeTexture(STexture* pTexture, const D3D11_SUBRESOURCE_DATA* pInitialData, uint32 uCPUAccess, CContext* pContext, const SGIFormatInfo* pFormatInfo)
{
pTexture->m_pfUpdateSubresource = &UpdateTexSubresource<Impl>;
pTexture->m_pfMapSubresource = &MapTexSubresource<Impl>;
pTexture->m_pfUnmapSubresource = &UnmapTexSubresource<Impl>;
pTexture->m_pfUnpackData = &UnpackTexData<Impl>;
pTexture->m_pfPackData = &PackTexData<Impl>;
pTexture->m_pfLocatePackedDataFunc = &LocateTexPackedData<Impl>;
Impl::AllocateResource(pTexture, pContext->GetDevice());
Impl::InitializeStorage(pTexture, uCPUAccess, pFormatInfo, pContext);
if (pInitialData)
{
STexBox kMipBox;
kMipBox.m_kOffset = STexPos(0, 0, 0);
STexSubresourceID kSubID;
for (kSubID.m_uElement = 0; kSubID.m_uElement < pTexture->m_uNumElements; ++kSubID.m_uElement)
{
for (kSubID.m_iMipLevel = 0; kSubID.m_iMipLevel < (GLint)pTexture->m_uNumMipLevels; ++kSubID.m_iMipLevel)
{
kMipBox.m_kSize = GetMipSize(pTexture, kSubID.m_iMipLevel, pFormatInfo, false);
Impl::UploadImage(pTexture, kSubID, kMipBox, pInitialData->pSysMem, pInitialData->SysMemPitch, pInitialData->SysMemSlicePitch, pContext, pFormatInfo);
++pInitialData;
}
}
}
pTexture->m_kCreationFence.IssueFence(pContext->GetDevice());
}
// Helper class to bind and unbind a framebuffer that is not being used for rendering
// but we still want to operate against. Necessary for OpenGL versions below 4.5 that
// don't have the glNamedFramebuffer* functions in the core api
struct AutoFramebufferBinder
{
GLint m_lastFbo;
GLenum m_fboTarget;
AutoFramebufferBinder(GLint fbo, GLenum target = GL_DRAW_FRAMEBUFFER)
{
m_fboTarget = target;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_lastFbo);
glBindFramebuffer(m_fboTarget, fbo);
}
~AutoFramebufferBinder()
{
glBindFramebuffer(m_fboTarget, m_lastFbo);
}
};
#if DXGLES || MAC || defined(DXGL_SUPPORTS_NAMED_FRAMEBUFFER_EXTENSION_FUNCTIONS)
#define CryGlCheckFramebufferStatus glCheckNamedFramebufferStatusEXT
#define CryGlNamedFramebufferTexture glNamedFramebufferTextureEXT
#define CryGlNamedFramebufferTextureLayer glNamedFramebufferTextureLayerEXT
#else
GLenum CheckFrameBufferStatus(GLuint framebufferObject, GLenum framebufferType)
{
AutoFramebufferBinder autoFboBinder(framebufferObject, framebufferType);
return glCheckFramebufferStatus(framebufferType);
}
void NamedFramebufferTexture(GLuint framebufferObject, GLenum attachmentId, GLuint texture, GLint mipLevel)
{
AutoFramebufferBinder autoFboBinder(framebufferObject);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, attachmentId, texture, mipLevel);
}
void NamedFramebufferTextureLayer(GLuint framebufferObject, GLenum attachmentId, GLuint texture, GLint mipLevel, GLint layer)
{
AutoFramebufferBinder autoFboBinder(framebufferObject);
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, attachmentId, texture, mipLevel, layer);
}
static PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC CryGlCheckFramebufferStatus = nullptr;
static PFNGLNAMEDFRAMEBUFFERTEXTUREPROC CryGlNamedFramebufferTexture = nullptr;
static PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC CryGlNamedFramebufferTextureLayer = nullptr;
#endif
void InitializeCryGlFramebufferFunctions()
{
// Making the function empty for DXGLES support since we just define the CryGL
// functions as the correct gl es functions.
#if !DXGLES && !MAC && !defined(DXGL_SUPPORTS_NAMED_FRAMEBUFFER_EXTENSION_FUNCTIONS)
static bool sAreCryGlFunctionsSet = false;
if (sAreCryGlFunctionsSet == false)
{
sAreCryGlFunctionsSet = true;
// We want to use the core API functions instead of the EXT functions because
// the EXT functions require that all textures that are bound to a FBO are of
// the same dimensions. When running OpenGL in the editor we can't run with
// that restriction (depth texture is the frame buffer size but the render to
// textures are smaller, hence a mismatch). Not all platforms support the core
// API (OpenGL 4.5 added the named versions, 3.0+ added the framebuffer objects
// with no size restrictions, ES/2.0 does not have the API but has the extensions)
// we need to select the version we are going to use here and hide the details
// from the calling code to keep it cleaner
CryGlCheckFramebufferStatus = DXGL_GL_LOADER_FUNCTION_PTR_PREFIX(CheckNamedFramebufferStatusEXT);
#if !USE_NVIDIA_NISGHT
if (DXGL_GL_LOADER_FUNCTION_PTR_PREFIX(CheckNamedFramebufferStatus))
{
CryGlCheckFramebufferStatus = DXGL_GL_LOADER_FUNCTION_PTR_PREFIX(CheckNamedFramebufferStatus);
}
else if (DXGL_GL_LOADER_FUNCTION_PTR_PREFIX(CheckFramebufferStatus))
#endif
{
CryGlCheckFramebufferStatus = (PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC)&CheckFrameBufferStatus;
}
CryGlNamedFramebufferTexture = DXGL_GL_LOADER_FUNCTION_PTR_PREFIX(NamedFramebufferTextureEXT);
#if !USE_NVIDIA_NISGHT
if (DXGL_GL_LOADER_FUNCTION_PTR_PREFIX(NamedFramebufferTexture))
{
CryGlNamedFramebufferTexture = DXGL_GL_LOADER_FUNCTION_PTR_PREFIX(NamedFramebufferTexture);
}
else if (DXGL_GL_LOADER_FUNCTION_PTR_PREFIX(FramebufferTexture))
#endif
{
CryGlNamedFramebufferTexture = (PFNGLNAMEDFRAMEBUFFERTEXTUREPROC)&NamedFramebufferTexture;
}
CryGlNamedFramebufferTextureLayer = DXGL_GL_LOADER_FUNCTION_PTR_PREFIX(NamedFramebufferTextureLayerEXT);
#if !USE_NVIDIA_NISGHT
if (DXGL_GL_LOADER_FUNCTION_PTR_PREFIX(NamedFramebufferTextureLayer))
{
CryGlNamedFramebufferTextureLayer = DXGL_GL_LOADER_FUNCTION_PTR_PREFIX(NamedFramebufferTextureLayer);
}
else if (DXGL_GL_LOADER_FUNCTION_PTR_PREFIX(FramebufferTexture))
#endif
{
CryGlNamedFramebufferTextureLayer = (PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC)&NamedFramebufferTextureLayer;
}
}
#endif
}
SFrameBufferConfiguration::SFrameBufferConfiguration()
{
memset(m_akAttachments, 0, sizeof(m_akAttachments));
}
GLenum SFrameBufferConfiguration::AttachmentIndexToID(uint32 uIndex)
{
if (uIndex >= FIRST_COLOR_ATTACHMENT_INDEX &&
uIndex < FIRST_COLOR_ATTACHMENT_INDEX + MAX_COLOR_ATTACHMENTS)
{
return GL_COLOR_ATTACHMENT0 + uIndex - FIRST_COLOR_ATTACHMENT_INDEX;
}
if (uIndex == DEPTH_ATTACHMENT_INDEX)
{
return GL_DEPTH_ATTACHMENT;
}
if (uIndex == STENCIL_ATTACHMENT_INDEX)
{
return GL_STENCIL_ATTACHMENT;
}
return GL_NONE;
}
uint32 SFrameBufferConfiguration::AttachmentIDToIndex(GLenum eID)
{
if (eID >= GL_COLOR_ATTACHMENT0 &&
eID < GL_COLOR_ATTACHMENT0 + MAX_COLOR_ATTACHMENTS)
{
return FIRST_COLOR_ATTACHMENT_INDEX + eID - GL_COLOR_ATTACHMENT0;
}
if (eID == GL_DEPTH_ATTACHMENT)
{
return DEPTH_ATTACHMENT_INDEX;
}
if (eID == GL_STENCIL_ATTACHMENT)
{
return STENCIL_ATTACHMENT_INDEX;
}
return MAX_ATTACHMENTS;
}
SSharingFence::SSharingFence()
#if DXGL_SHARED_OBJECT_SYNCHRONIZATION
: m_pFence(NULL)
#endif //DXGL_SHARED_OBJECT_SYNCHRONIZATION
{
}
SSharingFence::~SSharingFence()
{
#if DXGL_SHARED_OBJECT_SYNCHRONIZATION
if (m_pFence != NULL)
{
glDeleteSync(m_pFence);
}
#endif //DXGL_SHARED_OBJECT_SYNCHRONIZATION
}
void SSharingFence::IssueFence(CDevice*, bool bAvoidFlushing)
{
#if DXGL_SHARED_OBJECT_SYNCHRONIZATION
assert(m_pFence == NULL);
m_akWaitIssued.SetZero();
m_pFence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
DXGL_TODO(
"Check whether flushing here has performance implications, and if so find "
"a place that would make it less frequent. It can be avoided on drivers "
"that prehemptively flush every now and then, otherwise IssueWait could wait "
"indefinitely (or expire on server side, failing to synchronize).");
if (!bAvoidFlushing)
{
glFlush();
}
#endif //DXGL_SHARED_OBJECT_SYNCHRONIZATION
}
void SSharingFence::IssueWait(CContext* pContext)
{
#if DXGL_SHARED_OBJECT_SYNCHRONIZATION
if (m_pFence && !m_akWaitIssued.Get(pContext->GetIndex()))
{
#if DXGL_SERVER_SIDE_SHARED_OBJECT_SYNCHRONIZATION
glWaitSync(m_pFence, 0, GL_TIMEOUT_IGNORED);
m_akWaitIssued.Set(pContext->GetIndex(), true);
#else
while (glClientWaitSync(m_pFence, 0, 100) == GL_TIMEOUT_EXPIRED)
{
}
m_akWaitIssued.SetOne();
#endif
}
#endif //DXGL_SHARED_OBJECT_SYNCHRONIZATION
}
SResourceNamePool::SResourceNamePool()
: m_pBlocksHead(NULL)
{
}
SResourceNamePool::~SResourceNamePool()
{
LockCriticalSection(&m_kBlockSection);
while (m_pBlocksHead != NULL)
{
TBlockHeader* pBlockHeader(alias_cast<TBlockHeader*>(m_pBlocksHead));
TSlot* pNextBlock(pBlockHeader->m_pNext);
if (AtomicDecrement(&pBlockHeader->m_uRefCount))
{
TSlot* pSlot(m_pBlocksHead + NUM_HEADER_SLOTS + 1);
TSlot* pEnd(pSlot + pBlockHeader->m_uSize);
while (pSlot < pEnd)
{
pSlot->~TSlot();
++pSlot;
}
pBlockHeader->~TBlockHeader();
Free(m_pBlocksHead);
}
m_pBlocksHead = pNextBlock;
}
UnlockCriticalSection(&m_kBlockSection);
}
CResourceName SResourceNamePool::Create(GLuint uName)
{
TSlot* pBlock(m_pBlocksHead);
while (pBlock != NULL)
{
TBlockHeader* pBlockHeader(alias_cast<TBlockHeader*>(pBlock));
TSlot* pNextBlock(pBlockHeader->m_pNext);
TSlot* pFreeSlot(alias_cast<TSlot*>(pBlockHeader->m_kFreeList.Pop()));
if (pFreeSlot != NULL)
{
pFreeSlot->m_kUsed.m_pBlock = pBlock;
pFreeSlot->m_kUsed.m_uName = uName;
pFreeSlot->m_kUsed.m_uRefCount = 0;
return CResourceName(pFreeSlot);
}
pBlock = pNextBlock;
}
LockCriticalSection(&m_kBlockSection);
uint32 uNewBlockSize(m_pBlocksHead == NULL ? MIN_BLOCK_SIZE : alias_cast<TBlockHeader*>(m_pBlocksHead)->m_uSize * GROWTH_FACTOR);
TSlot* pNewBlock(static_cast<TSlot*>(Malloc(sizeof(TSlot) * (NUM_HEADER_SLOTS + max(1u, uNewBlockSize)))));
TBlockHeader* pNewBlockHeader(alias_cast<TBlockHeader*>(pNewBlock));
new (pNewBlockHeader) TBlockHeader();
pNewBlockHeader->m_pNext = m_pBlocksHead;
pNewBlockHeader->m_pPool = this;
pNewBlockHeader->m_uRefCount = 1;
pNewBlockHeader->m_uSize = uNewBlockSize;
m_pBlocksHead = pNewBlock;
UnlockCriticalSection(&m_kBlockSection);
TSlot* pFreeSlot(pNewBlock + NUM_HEADER_SLOTS + 1);
TSlot* pFreeSlotsEnd(pNewBlock + uNewBlockSize);
while (pFreeSlot != pFreeSlotsEnd)
{
new (pFreeSlot) TSlot;
pNewBlockHeader->m_kFreeList.Push(pFreeSlot->m_kNextFree);
++pFreeSlot;
}
TSlot* pUsedSlot(pNewBlock + NUM_HEADER_SLOTS);
new (pUsedSlot) TSlot;
pUsedSlot->m_kUsed.m_pBlock = pNewBlock;
pUsedSlot->m_kUsed.m_uName = uName;
pUsedSlot->m_kUsed.m_uRefCount = 0;
return CResourceName(pUsedSlot);
}
SResource::SResource()
: m_pfUpdateSubresource(NULL)
, m_pfMapSubresource(NULL)
, m_pfUnmapSubresource(NULL)
{
}
SResource::SResource(const SResource& kOther)
: m_kName(kOther.m_kName)
, m_pfUpdateSubresource(kOther.m_pfUpdateSubresource)
, m_pfMapSubresource(kOther.m_pfMapSubresource)
, m_pfUnmapSubresource(kOther.m_pfUnmapSubresource)
{
}
SResource::~SResource()
{
}
SFrameBufferObject::SFrameBufferObject()
: m_bUsesSRGB(false)
{
}
SFrameBufferObject::~SFrameBufferObject()
{
}
SFrameBuffer::SFrameBuffer(const SFrameBufferConfiguration& kConfiguration)
: m_kConfiguration(kConfiguration)
, m_pContext(NULL)
, m_uNumDrawBuffers(0)
{
}
SFrameBuffer::~SFrameBuffer()
{
if (m_kObject.m_kName.IsValid() &&
m_kObject.m_kName.GetName() != 0) // Index 0 is reserved for default FBO
{
GLuint uName(m_kObject.m_kName.GetName());
glDeleteFramebuffers(1, &uName);
}
}
void PrintFBOInfo(SFrameBuffer* pFrameBuffer, bool error = true)
{
static FILE* s_pFile = nullptr;
if (!s_pFile)
{
azfopen(&s_pFile, "fbo_info.txt", "w");
}
GLuint uFBOName(pFrameBuffer->m_kObject.m_kName.GetName());
fprintf(s_pFile, "Frame buffer %d Error: %d\n", uFBOName, error);
uint32 uAttachment;
for (uAttachment = 0; uAttachment < SFrameBufferConfiguration::MAX_ATTACHMENTS; ++uAttachment)
{
if (pFrameBuffer->m_kConfiguration.m_akAttachments[uAttachment] != NULL)
{
GLenum eAttachmentID(SFrameBufferConfiguration::AttachmentIndexToID(uAttachment));
fprintf(s_pFile, "\tAttachment #%d (0x%x) ", uFBOName, eAttachmentID);
GLint iParams[16], iTexName, iTexLevel;
glGetNamedFramebufferAttachmentParameterivEXT(uFBOName, eAttachmentID, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, iParams);
fprintf(s_pFile, "OBJECT_TYPE=0x%x ", iParams[0]);
glGetNamedFramebufferAttachmentParameterivEXT(uFBOName, eAttachmentID, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, iParams);
fprintf(s_pFile, "OBJECT_NAME=0x%x ", iParams[0]);
iTexName = iParams[0];
glGetNamedFramebufferAttachmentParameterivEXT(uFBOName, eAttachmentID, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL, iParams);
fprintf(s_pFile, "TEXTURE_LEVEL=0x%x ", iParams[0]);
iTexLevel = iParams[0];
glGetNamedFramebufferAttachmentParameterivEXT(uFBOName, eAttachmentID, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE, iParams);
fprintf(s_pFile, "TEXTURE_CUBE_MAP_FACE=0x%x ", iParams[0]);
glGetNamedFramebufferAttachmentParameterivEXT(uFBOName, eAttachmentID, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER, iParams);
#if !DXGLES
fprintf(s_pFile, "TEXTURE_LAYER=0x%x ", iParams[0]);
glGetNamedFramebufferAttachmentParameterivEXT(uFBOName, eAttachmentID, GL_FRAMEBUFFER_ATTACHMENT_LAYERED, iParams);
#endif
fprintf(s_pFile, "LAYERED=0x%x ", iParams[0]);
glGetNamedFramebufferAttachmentParameterivEXT(uFBOName, eAttachmentID, GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, iParams);
fprintf(s_pFile, "COLOR_ENCODING=0x%x ", iParams[0]);
glGetNamedFramebufferAttachmentParameterivEXT(uFBOName, eAttachmentID, GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE, iParams);
fprintf(s_pFile, "COMPONENT_TYPE=0x%x ", iParams[0]);
glGetNamedFramebufferAttachmentParameterivEXT(uFBOName, eAttachmentID, GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, iParams);
fprintf(s_pFile, "R=%d ", iParams[0]);
glGetNamedFramebufferAttachmentParameterivEXT(uFBOName, eAttachmentID, GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE, iParams);
fprintf(s_pFile, "G=%d ", iParams[0]);
glGetNamedFramebufferAttachmentParameterivEXT(uFBOName, eAttachmentID, GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE, iParams);
fprintf(s_pFile, "B=%d ", iParams[0]);
glGetNamedFramebufferAttachmentParameterivEXT(uFBOName, eAttachmentID, GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE, iParams);
fprintf(s_pFile, "A=%d ", iParams[0]);
glGetNamedFramebufferAttachmentParameterivEXT(uFBOName, eAttachmentID, GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE, iParams);
fprintf(s_pFile, "D=%d ", iParams[0]);
glGetNamedFramebufferAttachmentParameterivEXT(uFBOName, eAttachmentID, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, iParams);
fprintf(s_pFile, "S=%d ", iParams[0]);
fprintf(s_pFile, "\n\t\tTexture: ");
#if !DXGLES
// These are not available on GL ES
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_WIDTH, iParams);
fprintf(s_pFile, "WIDTH=%d ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_HEIGHT, iParams);
fprintf(s_pFile, "HEIGHT=%d ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_DEPTH, iParams);
fprintf(s_pFile, "DEPTH=%d ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_SAMPLES, iParams);
fprintf(s_pFile, "SAMPLES=%d ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_FIXED_SAMPLE_LOCATIONS, iParams);
fprintf(s_pFile, "FIXED_SAMPLE_LOCATIONS=%d ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_INTERNAL_FORMAT, iParams);
fprintf(s_pFile, "FIXED_SAMPLE_LOCATIONS=%d ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_RED_SIZE, iParams);
fprintf(s_pFile, "R=%d ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_GREEN_SIZE, iParams);
fprintf(s_pFile, "G=%d ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_BLUE_SIZE, iParams);
fprintf(s_pFile, "B=%d ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_ALPHA_SIZE, iParams);
fprintf(s_pFile, "A=%d ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_DEPTH_SIZE, iParams);
fprintf(s_pFile, "D=%d ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_STENCIL_SIZE, iParams);
fprintf(s_pFile, "S=%d ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_SHARED_SIZE, iParams);
fprintf(s_pFile, "SHR=%d ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_RED_TYPE, iParams);
fprintf(s_pFile, "RT=0x%x ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_GREEN_TYPE, iParams);
fprintf(s_pFile, "GT=0x%x ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_BLUE_TYPE, iParams);
fprintf(s_pFile, "BT=0x%x ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_ALPHA_TYPE, iParams);
fprintf(s_pFile, "AT=0x%x ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_DEPTH_TYPE, iParams);
fprintf(s_pFile, "DT=0x%x ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_COMPRESSED, iParams);
fprintf(s_pFile, "COMP=0x%x ", iParams[0]);
glGetTextureLevelParameterivEXT(iTexName, GL_TEXTURE_2D, iTexLevel, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, iParams);
#endif
fprintf(s_pFile, "COMP_SIZE=%d ", iParams[0]);
}
fprintf(s_pFile, "\n");
fflush(s_pFile);
}
}
bool SFrameBuffer::Validate()
{
GLenum eStatus(glCheckNamedFramebufferStatusEXT(m_kObject.m_kName.GetName(), GL_DRAW_FRAMEBUFFER));
if (eStatus != GL_FRAMEBUFFER_COMPLETE)
{
switch (eStatus)
{
case GL_FRAMEBUFFER_UNDEFINED:
DXGL_ERROR("Framebuffer is not complete: Default framebuffer does not exist");
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
DXGL_ERROR("Framebuffer is not complete: Any of the framebuffer attachment points are framebuffer incomplete");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
DXGL_ERROR("Framebuffer is not complete: Does not have at least one image attached to it");
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
DXGL_ERROR("Framebuffer is not complete: Unsupported framebuffer setup, check settings.");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
DXGL_ERROR("Framebuffer is not complete: Mismatch in multisample setup.");
break;
default:
DXGL_ERROR("Framebuffer is not complete (unknown status = %X)", eStatus);
}
return false;
}
return true;
}
void STextureState::ApplyFormatMode(GLuint uTexture, GLenum eTarget)
{
GLint aiSwizzleRGBA[4];
SwizzleMaskToRGBA(m_uSwizzleMask, aiSwizzleRGBA);
#if !DXGLES
glTextureParameterivEXT(uTexture, eTarget, GL_TEXTURE_SWIZZLE_RGBA, aiSwizzleRGBA);
#else
glTextureParameterivEXT(uTexture, eTarget, GL_TEXTURE_SWIZZLE_R, &aiSwizzleRGBA[0]);
glTextureParameterivEXT(uTexture, eTarget, GL_TEXTURE_SWIZZLE_G, &aiSwizzleRGBA[1]);
glTextureParameterivEXT(uTexture, eTarget, GL_TEXTURE_SWIZZLE_B, &aiSwizzleRGBA[2]);
glTextureParameterivEXT(uTexture, eTarget, GL_TEXTURE_SWIZZLE_A, &aiSwizzleRGBA[3]);
#endif
#if DXGL_SUPPORT_STENCIL_TEXTURES
if (m_iDepthStencilTextureMode)
{
glTextureParameteriEXT(uTexture, eTarget, GL_DEPTH_STENCIL_TEXTURE_MODE, m_iDepthStencilTextureMode);
}
#endif //DXGL_SUPPORT_STENCIL_TEXTURES
}
void STextureState::ApplyFormatMode(GLenum eTarget)
{
GLint aiSwizzleRGBA[4];
SwizzleMaskToRGBA(m_uSwizzleMask, aiSwizzleRGBA);
#if !DXGLES
glTexParameteriv(eTarget, GL_TEXTURE_SWIZZLE_RGBA, aiSwizzleRGBA);
#else
glTexParameteriv(eTarget, GL_TEXTURE_SWIZZLE_R, &aiSwizzleRGBA[0]);
glTexParameteriv(eTarget, GL_TEXTURE_SWIZZLE_G, &aiSwizzleRGBA[1]);
glTexParameteriv(eTarget, GL_TEXTURE_SWIZZLE_B, &aiSwizzleRGBA[2]);
glTexParameteriv(eTarget, GL_TEXTURE_SWIZZLE_A, &aiSwizzleRGBA[3]);
#endif
#if DXGL_SUPPORT_STENCIL_TEXTURES
if (m_iDepthStencilTextureMode)
{
glTexParameteri(eTarget, GL_DEPTH_STENCIL_TEXTURE_MODE, m_iDepthStencilTextureMode);
}
#endif //DXGL_SUPPORT_STENCIL_TEXTURES
}
void STextureState::Apply(GLuint uTexture, GLenum eTarget, const STextureUnitCache& kCurrentUnitCache)
{
#if (defined(glTextureParameteriEXT) && defined(glTextureParameterivEXT)) || !defined(USE_FAST_NAMED_APPROXIMATION)
ApplyFormatMode(uTexture, eTarget);
glTextureParameteriEXT(uTexture, eTarget, GL_TEXTURE_BASE_LEVEL, m_iBaseMipLevel);
glTextureParameteriEXT(uTexture, eTarget, GL_TEXTURE_MAX_LEVEL, m_iMaxMipLevel);
#else
switch (eTarget)
{
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
eTarget = GL_TEXTURE_CUBE_MAP;
break;
default:
eTarget = eTarget;
break;
}
glBindTexture(eTarget, uTexture);
ApplyFormatMode(eTarget);
glTexParameteri(eTarget, GL_TEXTURE_BASE_LEVEL, m_iBaseMipLevel);
glTexParameteri(eTarget, GL_TEXTURE_MAX_LEVEL, m_iMaxMipLevel);
if (kCurrentUnitCache.m_eTextureTarget == eTarget)
{
glBindTexture(kCurrentUnitCache.m_eTextureTarget, kCurrentUnitCache.m_kTextureName.GetName());
}
else
{
glBindTexture(eTarget, 0);
}
#endif
}
// Default value of -1000 is from the OpenGL spec and is the default value
// it uses when the min LOD is not specified.
static const float OPENGL_DEFAULT_MIN_LOD = -1000.0f;
STexture::STexture(GLsizei iWidth, GLsizei iHeight, GLsizei iDepth, GLenum eTarget, EGIFormat eFormat, uint32 uNumMipLevels, uint32 uNumElements)
: m_eTarget(eTarget)
, m_eFormat(eFormat)
, m_uNumMipLevels(uNumMipLevels)
, m_uNumElements(uNumElements)
, m_iWidth(iWidth)
, m_iHeight(iHeight)
, m_iDepth(iDepth)
, m_pShaderViewsHead(NULL)
, m_pOutputMergerViewsHead(NULL)
, m_pBoundModifier(NULL)
#if DXGL_USE_PBO_FOR_STAGING_TEXTURES
, m_akPixelBuffers(NULL)
#else
, m_pSystemMemoryCopy(NULL)
#endif
, m_fMinLod(OPENGL_DEFAULT_MIN_LOD)
{
#if DXGL_FULL_EMULATION
m_uNumElements = max(1u, m_uNumElements);
#endif //DXGL_FULL_EMULATION
#if defined(ANDROID)
ResetDontCareActionFlags();
#endif
}
STexture::~STexture()
{
if (m_kCopyImageView.IsValid())
{
GLuint uViewName(m_kCopyImageView.GetName());
if (uViewName != m_kName.GetName())
{
glDeleteTextures(1, &uViewName);
}
}
if (m_kName.IsValid())
{
GLuint uName(m_kName.GetName());
glDeleteTextures(1, &uName);
}
#if DXGL_USE_PBO_FOR_STAGING_TEXTURES
if (m_akPixelBuffers != NULL)
{
CResourceName* pPixelBuffersEnd(m_akPixelBuffers + m_uNumElements * m_uNumMipLevels);
for (CResourceName* pPixelBuffer = m_akPixelBuffers; pPixelBuffer < pPixelBuffersEnd; ++pPixelBuffer)
{
GLuint uName(pPixelBuffer->GetName());
glDeleteBuffers(1, &uName);
}
delete [] m_akPixelBuffers;
}
#else
if (m_pSystemMemoryCopy != NULL)
{
MemalignFree(m_pSystemMemoryCopy);
}
#endif
}
void STexture::SetMinLod(float minLod)
{
m_fMinLod = minLod;
glTextureParameterfEXT(m_kName.GetName(), m_eTarget, GL_TEXTURE_MIN_LOD, minLod);
}
SShaderTextureViewPtr STexture::CreateShaderResourceView(const SShaderTextureViewConfiguration& kConfiguration, CContext* pContext)
{
DXGL_TODO("This is not thread-safe, as multiple threads can create shader views for the same texture. Add synchronization primitive.");
SShaderTextureViewPtr spView(new SShaderTextureView(kConfiguration));
if (!spView->Init(this, pContext))
{
return NULL;
}
return spView;
}
SShaderImageViewPtr STexture::CreateUnorderedAccessView(const SShaderImageViewConfiguration& kConfiguration, CContext* pContext)
{
DXGL_TODO("This is not thread-safe, as multiple threads can create unordered access view for the same texture. Add synchronization primitive.");
SShaderImageViewPtr spView(new SShaderImageView(kConfiguration));
if (!spView->Init(this, pContext))
{
return NULL;
}
return spView;
}
SOutputMergerTextureViewPtr STexture::CreateOutputMergerView(const SOutputMergerTextureViewConfiguration& kConfiguration, CContext* pContext)
{
SOutputMergerTextureViewPtr spView(new SOutputMergerTextureView(this, kConfiguration));
if (!spView->Init(pContext))
{
return NULL;
}
return spView;
}
SOutputMergerTextureViewPtr STexture::GetCompatibleOutputMergerView(const SOutputMergerTextureViewConfiguration& kConfiguration, CContext* pContext)
{
DXGL_TODO("This is not thread-safe, as multiple threads can create output merger views for the same texture. Add synchronization primitive.");
SOutputMergerTextureView* pExistingView(m_pOutputMergerViewsHead);
while (pExistingView != NULL)
{
if (pExistingView->m_kConfiguration == kConfiguration)
{
return pExistingView;
}
pExistingView = pExistingView->m_pNextView;
}
return CreateOutputMergerView(kConfiguration, pContext);
}
#if defined(ANDROID)
void STexture::ResetDontCareActionFlags()
{
m_bColorLoadDontCare = false;
m_bDepthLoadDontCare = false;
m_bStencilLoadDontCare = false;
m_bColorStoreDontCare = false;
m_bDepthStoreDontCare = false;
m_bStencilStoreDontCare = false;
m_bColorStoreDontCareWhenUnbound = false;
m_bDepthStoreDontCareWhenUnbound = false;
m_bStencilStoreDontCareWhenUnbound = false;
m_bColorWasInvalidatedWhenUnbound = false;
m_bDepthWasInvalidatedWhenUnbound = false;
m_bStencilWasInvalidatedWhenUnbound = false;
}
void STexture::UpdateDontCareActionFlagsOnBound()
{
m_bColorStoreDontCareWhenUnbound = m_bColorStoreDontCare;
m_bDepthStoreDontCareWhenUnbound = m_bDepthStoreDontCare;
m_bStencilStoreDontCareWhenUnbound = m_bStencilStoreDontCare;
// open gl marks buffer invalid until it is cleared or something is rendered into it.
// If you bump into one of these asserts this means that you've dsicarded buffer content on
// resolve and try to restore. Although this behaviur is perfectly ok for Metal
// this won't work for GL. Render buffer won't be restored and might be either cleared
// or pixel state might become undefined (depending on GPU vendor).
assert((!m_bColorWasInvalidatedWhenUnbound) || (m_bColorWasInvalidatedWhenUnbound && m_bColorLoadDontCare));
assert((!m_bDepthWasInvalidatedWhenUnbound) || (m_bDepthWasInvalidatedWhenUnbound && m_bDepthLoadDontCare));
assert((!m_bStencilWasInvalidatedWhenUnbound) || (m_bStencilWasInvalidatedWhenUnbound && m_bStencilLoadDontCare));
m_bColorLoadDontCare = false;
m_bDepthLoadDontCare = false;
m_bStencilLoadDontCare = false;
m_bColorStoreDontCare = false;
m_bDepthStoreDontCare = false;
m_bStencilStoreDontCare = false;
m_bColorWasInvalidatedWhenUnbound = false;
m_bDepthWasInvalidatedWhenUnbound = false;
m_bStencilWasInvalidatedWhenUnbound = false;
}
void STexture::UpdateDontCareActionFlagsOnUnbound()
{
m_bColorWasInvalidatedWhenUnbound = m_bColorStoreDontCareWhenUnbound;
m_bDepthWasInvalidatedWhenUnbound = m_bDepthStoreDontCareWhenUnbound;
m_bStencilWasInvalidatedWhenUnbound = m_bStencilStoreDontCareWhenUnbound;
m_bColorStoreDontCareWhenUnbound = false;
m_bDepthStoreDontCareWhenUnbound = false;
m_bStencilStoreDontCareWhenUnbound = false;
}
#endif
#if DXGL_SUPPORT_APITRACE && defined(WIN32)
#if defined(WIN32)
uint32 SDynamicBufferCopy::ms_uPageSize = 0;
#endif //defined(WIN32)
SDynamicBufferCopy::SDynamicBufferCopy()
: m_pData(NULL)
, m_uSize(0)
#if defined(WIN32)
, m_apDirtyPages(NULL)
, m_uNumPages(0)
#endif //defined(WIN32)
{
}
SDynamicBufferCopy::~SDynamicBufferCopy()
{
Free();
}
uint8* SDynamicBufferCopy::Allocate(uint32 uSize)
{
m_uSize = uSize;
#if defined(WIN32)
if (ms_uPageSize == 0)
{
SYSTEM_INFO kInfo;
GetSystemInfo(&kInfo);
ms_uPageSize = kInfo.dwPageSize;
}
m_uNumPages = (uSize + ms_uPageSize - 1) / ms_uPageSize;
m_pData = reinterpret_cast<uint8*>(VirtualAlloc(NULL, m_uNumPages * ms_uPageSize, MEM_COMMIT | MEM_RESERVE | MEM_WRITE_WATCH, PAGE_READWRITE));
m_apDirtyPages = new void*[m_uNumPages];
return m_pData;
#else
#error "Not implemented on this platform"
#endif
}
void SDynamicBufferCopy::Free()
{
#if defined(WIN32)
if (m_pData != NULL)
{
VirtualFree(m_pData, 0, MEM_RELEASE);
}
delete [] m_apDirtyPages;
m_apDirtyPages = NULL;
#else
#error "Not implemented on this platform"
#endif
m_pData = NULL;
}
void SDynamicBufferCopy::ResetDirtyRegion()
{
#if defined(WIN32)
ResetWriteWatch(m_pData, m_uNumPages * ms_uPageSize);
#else
#error "Not implemented on this platform"
#endif
}
bool SDynamicBufferCopy::GetDirtyRegion(uint32& uOffset, uint32& uSize)
{
#if defined(WIN32)
ULONG uGranularity;
ULONG_PTR uCount(m_uNumPages);
if (GetWriteWatch(0, m_pData, m_uNumPages * ms_uPageSize, m_apDirtyPages, &uCount, &uGranularity) != 0)
{
return false;
}
uint32 uMin(0xFFFFFFFF), uMax(0);
uint32 uChange;
for (uChange = 0; uChange < uCount; ++uChange)
{
assert(m_apDirtyPages[uChange] >= m_pData);
uint32 uOffset((uint32)(reinterpret_cast<char*>(m_apDirtyPages[uChange]) - reinterpret_cast<char*>(m_pData)));
uMin = min(uMin, uOffset);
uMax = max(uMax, uOffset);
}
if (uMin > uMax)
{
uSize = 0;
uOffset = 0;
}
else
{
uMax = min(uMax + ms_uPageSize, m_uSize) - 1;
uOffset = uMin;
uSize = uMax - uMin + 1;
}
return true;
#else
#error "Not implemented on this platform"
#endif
}
#endif //DXGL_SUPPORT_APITRACE
SBuffer::SBuffer()
: m_pSystemMemoryCopy(NULL)
, m_bMapped(false)
, m_pTextureBuffersHead(NULL)
#if DXGL_SUPPORT_APITRACE
, m_bSystemMemoryCopyOwner(true)
#endif //DXGL_SUPPORT_APITRACE
#if DXGL_STREAMING_CONSTANT_BUFFERS
, m_bStreaming(false)
#endif //DXGL_STREAMING_CONSTANT_BUFFERS
{
}
SBuffer::~SBuffer()
{
if (m_kName.IsValid())
{
GLuint uName(m_kName.GetName());
glDeleteBuffers(1, &uName);
}
if (
#if DXGL_SUPPORT_APITRACE
m_bSystemMemoryCopyOwner &&
#endif //DXGL_SUPPORT_APITRACE
m_pSystemMemoryCopy != NULL)
{
MemalignFree(m_pSystemMemoryCopy);
}
}
SShaderViewPtr SBuffer::CreateShaderResourceView(EGIFormat eFormat, uint32 uFirstElement, uint32 uNumElements, uint32 uFlags, CContext* pContext)
{
DXGL_TODO("Consider uFlags as well if required")
if (m_uElementSize > 0) // Structured buffer
{
return CreateBufferView(uFirstElement, uNumElements, pContext);
}
SShaderTextureBufferViewConfiguration kTextureBufferConfiguration(eFormat, uFirstElement, uNumElements);
SShaderTextureBufferViewPtr spTextureBufferView(GetTextureBuffer(kTextureBufferConfiguration, pContext));
return spTextureBufferView;
}
SShaderViewPtr SBuffer::CreateUnorderedAccessView(EGIFormat eFormat, uint32 uFirstElement, uint32 uNumElements, uint32 uFlags, CContext* pContext)
{
DXGL_TODO("Consider uFlags as well if required")
if (m_uElementSize > 0) // Structured buffer
{
return CreateBufferView(uFirstElement, uNumElements, pContext);
}
SShaderTextureBufferViewConfiguration kTextureBufferConfiguration(eFormat, uFirstElement, uNumElements);
SShaderTextureBufferViewPtr spTextureBufferView(GetTextureBuffer(kTextureBufferConfiguration, pContext));
GLenum eImageFormat(GL_NONE);
if (!GetImageFormat(eFormat, &eImageFormat))
{
DXGL_ERROR("Unsupported format for unordered access view");
return NULL;
}
SShaderImageViewPtr spImageView(new SShaderImageView(SShaderImageViewConfiguration(eImageFormat, 0, -1, GL_READ_WRITE)));
if (!spImageView->Init(spTextureBufferView, pContext))
{
return NULL;
}
return spImageView;
}
SShaderTextureBufferViewPtr SBuffer::GetTextureBuffer(SShaderTextureBufferViewConfiguration& kConfiguration, CContext* pContext)
{
SShaderTextureBufferView* pExistingTextureBuffer(m_pTextureBuffersHead);
while (pExistingTextureBuffer != NULL)
{
if (pExistingTextureBuffer->m_kConfiguration == kConfiguration)
{
return pExistingTextureBuffer;
}
pExistingTextureBuffer = pExistingTextureBuffer->m_pNextView;
}
SShaderTextureBufferViewPtr spNewView(new SShaderTextureBufferView(kConfiguration));
if (!spNewView->Init(this, pContext))
{
return NULL;
}
return spNewView;
}
SShaderBufferViewPtr SBuffer::CreateBufferView(uint32 uFirstElement, uint32 uNumElements, CContext* pContext)
{
SBufferRange kRange(uFirstElement * m_uElementSize, uNumElements * m_uElementSize);
SShaderBufferView* pBufferView;
if (kRange.m_uOffset == 0 && kRange.m_uSize == m_uSize)
{
pBufferView = new SShaderBufferView(SBufferRange());
}
else
{
pBufferView = new SShaderBufferView(kRange);
}
pBufferView->Init(this, pContext);
return pBufferView;
}
SQuery::~SQuery()
{
}
void SQuery::Begin()
{
}
void SQuery::End()
{
}
uint32 SQuery::GetDataSize()
{
return 0;
}
SPlainQuery::SPlainQuery(GLenum eTarget)
: m_eTarget(eTarget)
, m_bBegun(false)
{
}
SPlainQuery::~SPlainQuery()
{
glDeleteQueries(1, &m_uName);
}
void SPlainQuery::Begin()
{
glBeginQuery(m_eTarget, m_uName);
m_bBegun = true;
}
void SPlainQuery::End()
{
glEndQuery(m_eTarget);
}
SOcclusionQuery::SOcclusionQuery()
#if DXGLES
// GLES does not have GL_SAMPLES_PASSED
: SPlainQuery(GL_ANY_SAMPLES_PASSED)
#else
: SPlainQuery(GL_SAMPLES_PASSED)
#endif
{
}
bool SOcclusionQuery::GetData(void* pData, uint32 uDataSize, bool bFlush)
{
if (m_bBegun) // Query objects are only defined after the first glBeginQuery call
{
GLuint uResultAvailable(GL_FALSE);
glGetQueryObjectuiv(m_uName, GL_QUERY_RESULT_AVAILABLE, &uResultAvailable);
// Prevent garbage reads https://plus.google.com/+RomainGuy/posts/DgemC8aa7qH
if ((uResultAvailable & GL_TRUE) == GL_TRUE)
{
#if DXGLES
GLuint uResult;
glGetQueryObjectuiv(m_uName, GL_QUERY_RESULT, &uResult);
#else
GLuint64 uResult;
glGetQueryObjectui64v(m_uName, GL_QUERY_RESULT, &uResult);
#endif
*reinterpret_cast<UINT64*>(pData) = uResult;
return true;
}
}
return false;
}
uint32 SOcclusionQuery::GetDataSize()
{
return (uint32)sizeof(UINT64);
}
SFenceSync::SFenceSync()
: m_pFence(NULL)
{
}
SFenceSync::~SFenceSync()
{
if (m_pFence)
{
glDeleteSync(m_pFence);
}
}
void SFenceSync::End()
{
if (m_pFence)
{
glDeleteSync(m_pFence);
}
m_pFence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
AZ_Assert(m_pFence, "Failed to create fence");
}
bool SFenceSync::GetData(void* pData, uint32 uDataSize, bool bFlush)
{
assert(m_pFence != NULL);
GLbitfield flags = 0;
if (bFlush)
{
if (gRenDev->GetFeatures() & RFT_HW_QUALCOMM)
{
// There's a driver bug with some Qualcomm devices that don't apply the GL_SYNC_FLUSH_COMMANDS_BIT flag.
// We manually do a glFlush before calling glClientWaitSync.
glFlush();
}
else
{
flags |= GL_SYNC_FLUSH_COMMANDS_BIT;
}
}
GLenum eResult(glClientWaitSync(m_pFence, flags, 0));
if (eResult != GL_TIMEOUT_EXPIRED)
{
*reinterpret_cast<BOOL*>(pData) = eResult == GL_WAIT_FAILED ? FALSE : TRUE;
return true;
}
return false;
}
uint32 SFenceSync::GetDataSize()
{
return (uint32)sizeof(BOOL);
}
#if DXGL_SUPPORT_TIMER_QUERIES
bool STimestampDisjointQuery::GetData(void* pData, uint32 uDataSize, bool bFlush)
{
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT* pTimestampDisjoint(alias_cast<D3D11_QUERY_DATA_TIMESTAMP_DISJOINT*>(pData));
pTimestampDisjoint->Frequency = 1000000000; // Timestamps are expressed in nanoseconds
DXGL_TODO("Check if there's a way to detect the reliability of timestamps/time elapsed");
pTimestampDisjoint->Disjoint = FALSE;
return true;
}
uint32 STimestampDisjointQuery::GetDataSize()
{
return (uint32)sizeof(D3D11_QUERY_DATA_TIMESTAMP_DISJOINT);
}
STimestampQuery::STimestampQuery()
{
glGenQueries(1, &m_uName);
}
STimestampQuery::~STimestampQuery()
{
glDeleteQueries(1, &m_uName);
}
void STimestampQuery::End()
{
glQueryCounter(m_uName, GL_TIMESTAMP);
}
bool STimestampQuery::GetData(void* pData, uint32 uDataSize, bool bFlush)
{
GLint iAvailable;
glGetQueryObjectiv(m_uName, GL_QUERY_RESULT_AVAILABLE, &iAvailable);
if (iAvailable == 0 && bFlush)
{
glFlush();
glGetQueryObjectiv(m_uName, GL_QUERY_RESULT_AVAILABLE, &iAvailable);
}
if (iAvailable != 0)
{
GLuint64 uResult;
glGetQueryObjectui64v(m_uName, GL_QUERY_RESULT, &uResult);
UINT64* puTimestampData(alias_cast<UINT64*>(pData));
*puTimestampData = uResult;
return true;
}
return false;
}
uint32 STimestampQuery::GetDataSize()
{
return (uint32)sizeof(UINT64);
}
#endif //DXGL_SUPPORT_TIMER_QUERIES
SDefaultFrameBufferTexture::SDefaultFrameBufferTexture(GLsizei iWidth, GLsizei iHeight, EGIFormat eFormat, GLbitfield uBufferMask)
: STexture(iWidth, iHeight, 1, GL_TEXTURE_2D, eFormat, 1, 1)
, m_uBufferMask(uBufferMask)
, m_eInputColorBuffer(GL_INVALID_ENUM)
, m_eOutputColorBuffer(GL_INVALID_ENUM)
, m_uTextureRefCount(0)
, m_iDefaultFBOWidth(iWidth)
, m_iDefaultFBOHeight(iHeight)
, m_bInputDirty(false)
, m_bOutputDirty(false)
#if DXGL_FULL_EMULATION
, m_kCustomWindowContext(NULL)
#endif //DXGL_FULL_EMULATION
{
m_pfUpdateSubresource = &UpdateSubresource;
m_pfMapSubresource = &MapSubresource;
m_pfUnmapSubresource = &UnmapSubresource;
m_pfUnpackData = &UnpackData;
m_pfPackData = &PackData;
m_pfLocatePackedDataFunc = &LocatePackedData;
}
SDefaultFrameBufferTexture::~SDefaultFrameBufferTexture()
{
if (m_uTextureRefCount > 0)
{
ReleaseTexture();
}
}
SShaderTextureViewPtr SDefaultFrameBufferTexture::CreateShaderResourceView(const SShaderTextureViewConfiguration& kConfiguration, CContext* pContext)
{
SShaderTextureViewPtr spView(new SDefaultFrameBufferShaderTextureView(kConfiguration));
if (!spView->Init(this, pContext))
{
return NULL;
}
return spView;
}
SShaderImageViewPtr SDefaultFrameBufferTexture::CreateUnorderedAccessView(const SShaderImageViewConfiguration& kConfiguration, CContext* pContext)
{
SShaderImageViewPtr spView(new SShaderImageView(kConfiguration));
if (!spView->Init(this, pContext))
{
return NULL;
}
return spView;
}
SOutputMergerTextureViewPtr SDefaultFrameBufferTexture::CreateOutputMergerView(const SOutputMergerTextureViewConfiguration& kConfiguration, CContext* pContext)
{
SOutputMergerTextureViewPtr spView(new SDefaultFrameBufferOutputMergerView(this, kConfiguration));
if (!spView->Init(pContext))
{
return NULL;
}
return spView;
}
void SDefaultFrameBufferTexture::OnCopyRead(CContext* pContext)
{
EnsureTextureExists(pContext);
OnRead(pContext);
}
void SDefaultFrameBufferTexture::OnCopyWrite(CContext* pContext)
{
EnsureTextureExists(pContext);
OnWrite(pContext, false);
}
void SDefaultFrameBufferTexture::IncTextureRefCount(CContext* pContext)
{
++m_uTextureRefCount;
if (m_uTextureRefCount == 1)
{
const SGIFormatInfo* pFormatInfo(GetGIFormatInfo(m_eFormat));
if (pFormatInfo == NULL || pFormatInfo->m_pTexture == NULL)
{
DXGL_ERROR("Invalid format for frame buffer texture (could not retrieve texture format info)");
return;
}
GLuint uName;
glGenTextures(1, &uName);
m_kName = pContext->GetDevice()->GetTextureNamePool().Create(uName);
if (pContext->GetDevice()->IsFeatureSupported(eF_CopyImage))
{
m_kCopyImageView = m_kName;
m_eCopyImageTarget = m_eTarget;
}
m_kInputFBO.m_bUsesSRGB = pFormatInfo->m_pTexture->m_bSRGB;
m_kDefaultFBO.m_bUsesSRGB = pFormatInfo->m_pTexture->m_bSRGB;
#if DXGL_USE_IMMUTABLE_TEXTURES
glTextureStorage2DEXT(uName, m_eTarget, m_uNumMipLevels, pFormatInfo->m_pTexture->m_iInternalFormat, m_iWidth, m_iHeight);
#else
glTextureImage2DEXT(uName, m_eTarget, 0, pFormatInfo->m_pTexture->m_iInternalFormat, m_iWidth, m_iHeight, 0, pFormatInfo->m_pTexture->m_eBaseFormat, pFormatInfo->m_pTexture->m_eDataType, NULL);
#endif
GLuint uInputFBOName;
#if !DXGLES && !USE_NVIDIA_NISGHT && !MAC
if (glCreateFramebuffers)
{
// Use create framebuffers instead of gen otherwise we would have to
// bind the framebuffer once to create the actual FBO before we can
// call the glNamedFramebuffer* functions. If this function does not
// exist, then the glNamedFramebuffers will not either and we handle
// that case already
glCreateFramebuffers(1, &uInputFBOName);
}
else
#endif
{
glGenFramebuffers(1, &uInputFBOName);
}
m_kInputFBO.m_kName = pContext->GetDevice()->GetFrameBufferNamePool().Create(uInputFBOName);
if ((m_uBufferMask & GL_COLOR_BUFFER_BIT) != 0)
{
glNamedFramebufferTextureEXT(uInputFBOName, GL_COLOR_ATTACHMENT0, uName, 0);
m_eInputColorBuffer = GL_COLOR_ATTACHMENT0;
#if !DXGLES
m_eOutputColorBuffer = GL_BACK_LEFT; // This has to be one of GL_BACK_LEFT, GL_BACK_RIGHT, GL_FRONT_LEFT, GL_FRONT_RIGHT or glDrawBuffer will fail
#else
#if defined(IOS)
// There is no default framebuffer on IOS. There is only one created by the UIKit API.
m_eOutputColorBuffer = GL_COLOR_ATTACHMENT0;
# else
m_eOutputColorBuffer = GL_BACK;
# endif // defined(IOS)
#endif
}
else
{
m_eInputColorBuffer = GL_NONE;
m_eOutputColorBuffer = GL_NONE;
}
if ((m_uBufferMask & GL_DEPTH_BUFFER_BIT) != 0)
{
glNamedFramebufferTextureEXT(uInputFBOName, GL_DEPTH_ATTACHMENT, uName, 0);
}
if ((m_uBufferMask & GL_STENCIL_BUFFER_BIT) != 0)
{
glNamedFramebufferTextureEXT(uInputFBOName, GL_STENCIL_ATTACHMENT, uName, 0);
}
GLenum eStatus(glCheckNamedFramebufferStatusEXT(uInputFBOName, GL_DRAW_FRAMEBUFFER));
if (eStatus != GL_FRAMEBUFFER_COMPLETE)
{
DXGL_ERROR("Default input framebuffer is not complete (status = %d)", eStatus);
glDeleteFramebuffers(1, &uInputFBOName);
m_kInputFBO.m_kName = CResourceName();
}
//TODO: Remove this hack to clear the default engine framebuffer color buffer on startup
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, uInputFBOName);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, uInputFBOName);
}
}
void SDefaultFrameBufferTexture::DecTextureRefCount()
{
// Custom FBO
--m_uTextureRefCount;
if (m_uTextureRefCount == 0)
{
ReleaseTexture();
}
}
void SDefaultFrameBufferTexture::EnsureTextureExists(CContext* pContext)
{
if (m_uTextureRefCount == 0)
{
DXGL_WARNING("Extra default framebuffer texture was forced as a fallback for a currently missing implementation");
IncTextureRefCount(pContext);
}
}
void SDefaultFrameBufferTexture::ReleaseTexture()
{
m_kInputFBOColorTextureView = nullptr;
if (m_kInputFBO.m_kName.IsValid())
{
GLuint uInputFBOName(m_kInputFBO.m_kName.GetName());
glDeleteFramebuffers(1, &uInputFBOName);
m_kInputFBO.m_kName = CResourceName();
}
if (m_kName.IsValid())
{
GLuint uTextureName(m_kName.GetName());
glDeleteTextures(1, &uTextureName);
m_kName = CResourceName();
}
m_kCopyImageView = m_kName;
}
void SDefaultFrameBufferTexture::OnWrite(CContext* pContext, bool bDefaultFrameBuffer)
{
#if DXGL_FULL_EMULATION
if (m_kCustomWindowContext != NULL)
{
pContext->SetWindowContext(m_kCustomWindowContext);
}
#endif //DXGL_FULL_EMULATION
if (bDefaultFrameBuffer)
{
m_bInputDirty = true; // Default frame buffer - write to output directly
}
else
{
m_bOutputDirty = true; // Custom FBO - write to input
}
}
void SDefaultFrameBufferTexture::OnRead(CContext* pContext)
{
if (m_bInputDirty)
{
// Copy default buffer (output) to texture (input)
pContext->BlitFrameBuffer(
m_kDefaultFBO, m_kInputFBO,
m_eOutputColorBuffer, m_eInputColorBuffer,
#if CRY_OPENGL_FLIP_Y
0, m_iDefaultFBOHeight, m_iDefaultFBOWidth, 0,
#else
0, 0, m_iDefaultFBOWidth, m_iDefaultFBOHeight,
#endif
0, 0, m_iWidth, m_iHeight,
m_uBufferMask, (m_iDefaultFBOWidth == m_iWidth) ? GL_NEAREST : GL_LINEAR);
}
}
void SDefaultFrameBufferTexture::Flush(CContext* pContext)
{
if (m_bOutputDirty)
{
GLint iSrcYMin = 0;
GLint iSrcYMax = m_iHeight;
#if CRY_OPENGL_FLIP_Y
AZStd::swap(iSrcYMin, iSrcYMax);
#endif
// Copy texture (input) to default buffer (output)
GLenum filter = (m_iDefaultFBOWidth == m_iWidth) ? GL_NEAREST : GL_LINEAR;
uint32 glVersion = pContext->GetDevice()->GetFeatureSpec().m_kVersion.ToUint();
if (DXGLES && glVersion == DXGLES_VERSION_30 && gRenDev->GetFeatures() & RFT_HW_QUALCOMM)
{
// OpenGLES 3.0 Qualcomm driver has a bug that rotates the image 90 degrees when doing a
// glBlitFramebuffer into the default framebuffer when in landscape mode. Because of this we
// do the blitting using a shader instead.
if (!m_kInputFBOColorTextureView)
{
SShaderTextureViewConfiguration conf(m_eFormat, m_eTarget, 0, m_uNumMipLevels, 0, m_uNumElements);
m_kInputFBOColorTextureView = CreateShaderResourceView(conf, pContext);
}
pContext->BlitTextureToFrameBuffer(
m_kInputFBOColorTextureView,
m_kDefaultFBO,
m_eOutputColorBuffer,
0, iSrcYMin, m_iWidth, iSrcYMax,
0, 0, m_iDefaultFBOWidth, m_iDefaultFBOHeight,
filter, filter);
}
else
{
pContext->BlitFrameBuffer(
m_kInputFBO, m_kDefaultFBO,
m_eInputColorBuffer, m_eOutputColorBuffer,
0, iSrcYMin, m_iWidth, iSrcYMax,
0, 0, m_iDefaultFBOWidth, m_iDefaultFBOHeight,
m_uBufferMask, filter);
}
}
}
#if DXGL_FULL_EMULATION
void SDefaultFrameBufferTexture::SetCustomWindowContext(const TWindowContext& kCustomWindowContext)
{
m_kCustomWindowContext = kCustomWindowContext;
}
#endif //DXGL_FULL_EMULATION
typedef SSingleTexImpl<STex2DUncompressed, STexPartition> TDefaultFrameBufferTextureImpl;
void SDefaultFrameBufferTexture::UpdateSubresource(SResource* pResource, uint32 uSubresource, const D3D11_BOX* pDstBox, const void* pSrcData, uint32 uSrcRowPitch, uint32 uSrcDepthPitch, CContext* pContext)
{
SDefaultFrameBufferTexture* pDefaultFrameBufferTexture = static_cast<SDefaultFrameBufferTexture*>(pResource);
DXGL_TODO(
"Currently only the texture FBO case is handled so we have to make sure that the texture "
"exists during this function call. The default framebuffer case should be supported too.");
pDefaultFrameBufferTexture->EnsureTextureExists(pContext);
if (uSubresource > 0)
{
DXGL_ERROR("The only valid subresource index for the default frame buffer is 0 - cannot update subresource");
return;
}
UpdateTexSubresource<TDefaultFrameBufferTextureImpl>(pDefaultFrameBufferTexture, uSubresource, pDstBox, pSrcData, uSrcRowPitch, uSrcDepthPitch, pContext);
pDefaultFrameBufferTexture->OnWrite(pContext, false);
}
bool SDefaultFrameBufferTexture::MapSubresource(SResource* pResource, uint32 uSubresource, D3D11_MAP MapType, UINT MapFlags, D3D11_MAPPED_SUBRESOURCE* pMappedResource, CContext* pContext)
{
SDefaultFrameBufferTexture* pDefaultFrameBufferTexture = static_cast<SDefaultFrameBufferTexture*>(pResource);
DXGL_TODO(
"Currently only the texture FBO case is handled so we have to make sure that the texture "
"exists during this function call. The default framebuffer case should be supported too.");
pDefaultFrameBufferTexture->EnsureTextureExists(pContext);
if (uSubresource > 0)
{
DXGL_ERROR("The only valid subresource index for the default frame buffer is 0 - cannot map subresource");
return false;
}
switch (MapType)
{
case D3D11_MAP_READ:
case D3D11_MAP_READ_WRITE:
pDefaultFrameBufferTexture->OnRead(pContext);
break;
case D3D11_MAP_WRITE:
break;
default:
DXGL_ERROR("Unsupported map operation type for default frame buffer");
return false;
}
return MapTexSubresource<TDefaultFrameBufferTextureImpl>(pDefaultFrameBufferTexture, uSubresource, MapType, MapFlags, pMappedResource, pContext);
}
void SDefaultFrameBufferTexture::UnmapSubresource(SResource* pResource, uint32 uSubresource, CContext* pContext)
{
SDefaultFrameBufferTexture* pDefaultFrameBufferTexture = static_cast<SDefaultFrameBufferTexture*>(pResource);
DXGL_TODO(
"Currently only the texture FBO case is handled so we have to make sure that the texture "
"exists during this function call. The default framebuffer case should be supported too.");
pDefaultFrameBufferTexture->EnsureTextureExists(pContext);
if (uSubresource > 0)
{
DXGL_ERROR("The only valid subresource index for the default frame buffer is 0 - cannot unmap subresource");
return;
}
if (pDefaultFrameBufferTexture->m_kMappedSubTextures.size() > 0 && pDefaultFrameBufferTexture->m_kMappedSubTextures.at(0).m_bUpload)
{
pDefaultFrameBufferTexture->OnWrite(pContext, false);
}
UnmapTexSubresource<TDefaultFrameBufferTextureImpl>(pDefaultFrameBufferTexture, uSubresource, pContext);
}
void SDefaultFrameBufferTexture::UnpackData(STexture* pTexture, STexSubresourceID kSubID, STexPos kOffset, STexSize kSize, const SMappedSubTexture& kDataLocation, CContext* pContext)
{
SDefaultFrameBufferTexture* pDefaultFrameBufferTexture = static_cast<SDefaultFrameBufferTexture*>(pTexture);
DXGL_TODO(
"Currently only the texture FBO case is handled so we have to make sure that the texture "
"exists during this function call. The default framebuffer case should be supported too.");
pDefaultFrameBufferTexture->EnsureTextureExists(pContext);
UnpackTexData<TDefaultFrameBufferTextureImpl>(pDefaultFrameBufferTexture, kSubID, kOffset, kSize, kDataLocation, pContext);
pDefaultFrameBufferTexture->OnWrite(pContext, false);
}
void SDefaultFrameBufferTexture::PackData(STexture* pTexture, STexSubresourceID kSubID, STexPos kOffset, STexSize kSize, const SMappedSubTexture& kDataLocation, CContext* pContext)
{
SDefaultFrameBufferTexture* pDefaultFrameBufferTexture = static_cast<SDefaultFrameBufferTexture*>(pTexture);
DXGL_TODO(
"Currently only the texture FBO case is handled so we have to make sure that the texture "
"exists during this function call. The default framebuffer case should be supported too.");
pDefaultFrameBufferTexture->EnsureTextureExists(pContext);
pDefaultFrameBufferTexture->OnRead(pContext);
PackTexData<TDefaultFrameBufferTextureImpl>(pDefaultFrameBufferTexture, kSubID, kOffset, kSize, kDataLocation, pContext);
}
uint32 SDefaultFrameBufferTexture::LocatePackedData(STexture* pTexture, STexSubresourceID kSubID, STexPos kOffset, SMappedSubTexture& kDataLocation)
{
DXGL_TODO(
"Currently only the texture FBO case is handled so we have to make sure that the texture "
"exists during this function call. The default framebuffer case should be supported too.");
return LocateTexPackedData<TDefaultFrameBufferTextureImpl>(pTexture, kSubID, kOffset, kDataLocation);
}
const SGIFormatInfo* GetCompatibleTextureFormatInfo(EGIFormat* peGIFormat)
{
const SGIFormatInfo* pFormatInfo(GetGIFormatInfo(*peGIFormat));
if (pFormatInfo->m_pTexture != NULL)
{
return pFormatInfo;
}
if (pFormatInfo->m_eTypelessFormat != eGIF_NUM && pFormatInfo->m_eTypelessFormat != *peGIFormat)
{
*peGIFormat = pFormatInfo->m_eTypelessFormat;
pFormatInfo = GetGIFormatInfo(pFormatInfo->m_eTypelessFormat);
if (pFormatInfo->m_pTexture != NULL)
{
return pFormatInfo;
}
}
*peGIFormat = eGIF_NUM;
return NULL;
}
STexturePtr CreateTexture1D(const D3D11_TEXTURE1D_DESC& kDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, CContext* pContext)
{
DXGL_SCOPED_PROFILE("CreateTexture1D")
EGIFormat eGIFormat(GetGIFormat(kDesc.Format));
const SGIFormatInfo* pFormatInfo(NULL);
if (eGIFormat == eGIF_NUM ||
(pFormatInfo = GetCompatibleTextureFormatInfo(&eGIFormat)) == NULL)
{
DXGL_ERROR("Invalid format for 1D texture");
return NULL;
}
uint32 uNumElements(kDesc.ArraySize);
bool bArray(kDesc.ArraySize > 1 || (kDesc.MiscFlags & D3D11_RESOURCE_MISC_DXGL_FORCE_ARRAY));
STexturePtr spTexture(
new STexture(
kDesc.Width, 1, 1,
bArray ? GL_TEXTURE_1D : GL_TEXTURE_1D_ARRAY,
eGIFormat, GetNumMipLevels(kDesc), kDesc.ArraySize));
if (kDesc.Usage == D3D11_USAGE_STAGING)
{
if (pFormatInfo->m_pTexture->m_bCompressed)
{
InitializeTexture<SStagingTexImpl<STex1DCompressed> >(spTexture, pInitialData, kDesc.CPUAccessFlags, pContext, pFormatInfo);
}
else
{
InitializeTexture<SStagingTexImpl<STex1DUncompressed> >(spTexture, pInitialData, kDesc.CPUAccessFlags, pContext, pFormatInfo);
}
}
else
{
if (pFormatInfo->m_pTexture->m_bCompressed)
{
if (bArray)
{
InitializeTexture<SArrayTexImpl<STex2DCompressed> >(spTexture, pInitialData, kDesc.CPUAccessFlags, pContext, pFormatInfo);
}
else
{
InitializeTexture<SSingleTexImpl<STex1DCompressed> >(spTexture, pInitialData, kDesc.CPUAccessFlags, pContext, pFormatInfo);
}
}
else
{
if (bArray)
{
InitializeTexture<SArrayTexImpl<STex2DUncompressed> >(spTexture, pInitialData, kDesc.CPUAccessFlags, pContext, pFormatInfo);
}
else
{
InitializeTexture<SSingleTexImpl<STex1DUncompressed> >(spTexture, pInitialData, kDesc.CPUAccessFlags, pContext, pFormatInfo);
}
}
}
return spTexture;
}
template <typename Partition>
void InitializeTexture2D(STexture* pTexture, bool bArray, bool bStaging, const D3D11_SUBRESOURCE_DATA* pInitialData, uint32 uCPUAccess, CContext* pContext, const SGIFormatInfo* pFormatInfo)
{
if (bStaging)
{
if (pFormatInfo->m_pTexture->m_bCompressed)
{
InitializeTexture<SStagingTexImpl<STex2DCompressed> >(pTexture, pInitialData, uCPUAccess, pContext, pFormatInfo);
}
else
{
InitializeTexture<SStagingTexImpl<STex2DUncompressed> >(pTexture, pInitialData, uCPUAccess, pContext, pFormatInfo);
}
}
else
{
if (pFormatInfo->m_pTexture->m_bCompressed)
{
if (bArray)
{
InitializeTexture<SArrayTexImpl<STex3DCompressed, Partition> >(pTexture, pInitialData, uCPUAccess, pContext, pFormatInfo);
}
else
{
InitializeTexture<SSingleTexImpl<STex2DCompressed, Partition> >(pTexture, pInitialData, uCPUAccess, pContext, pFormatInfo);
}
}
else
{
if (bArray)
{
InitializeTexture<SArrayTexImpl<STex3DUncompressed, Partition> >(pTexture, pInitialData, uCPUAccess, pContext, pFormatInfo);
}
else
{
InitializeTexture<SSingleTexImpl<STex2DUncompressed, Partition> >(pTexture, pInitialData, uCPUAccess, pContext, pFormatInfo);
}
}
}
}
STexturePtr CreateTexture2D(const D3D11_TEXTURE2D_DESC& kDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, CContext* pContext)
{
DXGL_SCOPED_PROFILE("CreateTexture2D")
EGIFormat eGIFormat(GetGIFormat(kDesc.Format));
const SGIFormatInfo* pFormatInfo(NULL);
if (eGIFormat == eGIF_NUM ||
(pFormatInfo = GetCompatibleTextureFormatInfo(&eGIFormat)) == NULL)
{
DXGL_ERROR("Invalid format for 2D texture");
return NULL;
}
bool bStaging(kDesc.Usage == D3D11_USAGE_STAGING);
if (kDesc.SampleDesc.Count > 1)
{
DXGL_NOT_IMPLEMENTED
return NULL;
}
else
{
if ((kDesc.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) != 0)
{
bool bArray(kDesc.ArraySize > 6 || (kDesc.MiscFlags & D3D11_RESOURCE_MISC_DXGL_FORCE_ARRAY));
#if DXGL_FULL_EMULATION
if (!pContext->GetDevice()->IsFeatureSupported(eF_TextureViews))
{
// Hack to specify array of textures with a single element without using texture views
if (kDesc.ArraySize == 0)
{
bArray = true;
}
}
#endif //DXGL_FULL_EMULATION
#if !DXGL_SUPPORT_CUBEMAP_ARRAYS
if (bArray)
{
DXGL_NOT_IMPLEMENTED;
return NULL;
}
STexturePtr spTexture(
new STexture(
kDesc.Width, kDesc.Height, 1,
GL_TEXTURE_CUBE_MAP,
eGIFormat, GetNumMipLevels(kDesc), kDesc.ArraySize));
#else
STexturePtr spTexture(
new STexture(
kDesc.Width, kDesc.Height, 1,
bArray ? GL_TEXTURE_CUBE_MAP_ARRAY : GL_TEXTURE_CUBE_MAP,
eGIFormat, GetNumMipLevels(kDesc), kDesc.ArraySize));
#endif
InitializeTexture2D<SCubePartition>(spTexture, bArray, bStaging, pInitialData, kDesc.CPUAccessFlags, pContext, pFormatInfo);
return spTexture;
}
else
{
bool bArray(kDesc.ArraySize > 1 || (kDesc.MiscFlags & D3D11_RESOURCE_MISC_DXGL_FORCE_ARRAY));
STexturePtr spTexture(
new STexture(
kDesc.Width, kDesc.Height, 1,
bArray ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D,
eGIFormat, GetNumMipLevels(kDesc), kDesc.ArraySize));
InitializeTexture2D<STexPartition>(spTexture, bArray, bStaging, pInitialData, kDesc.CPUAccessFlags, pContext, pFormatInfo);
return spTexture;
}
}
}
STexturePtr CreateTexture3D(const D3D11_TEXTURE3D_DESC& kDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, CContext* pContext)
{
DXGL_SCOPED_PROFILE("CreateTexture3D")
EGIFormat eGIFormat(GetGIFormat(kDesc.Format));
const SGIFormatInfo* pFormatInfo(NULL);
if (eGIFormat == eGIF_NUM ||
(pFormatInfo = GetCompatibleTextureFormatInfo(&eGIFormat)) == NULL)
{
DXGL_ERROR("Invalid format for 3D texture");
return NULL;
}
STexturePtr spTexture(
new STexture(
kDesc.Width, kDesc.Height, kDesc.Depth,
GL_TEXTURE_3D,
eGIFormat, GetNumMipLevels(kDesc), 1));
if (kDesc.Usage == D3D11_USAGE_STAGING)
{
if (pFormatInfo->m_pTexture->m_bCompressed)
{
InitializeTexture<SStagingTexImpl<STex3DCompressed> >(spTexture, pInitialData, kDesc.CPUAccessFlags, pContext, pFormatInfo);
}
else
{
InitializeTexture<SStagingTexImpl<STex3DUncompressed> >(spTexture, pInitialData, kDesc.CPUAccessFlags, pContext, pFormatInfo);
}
}
else
{
if (pFormatInfo->m_pTexture->m_bCompressed)
{
InitializeTexture<SSingleTexImpl<STex3DCompressed> >(spTexture, pInitialData, kDesc.CPUAccessFlags, pContext, pFormatInfo);
}
else
{
InitializeTexture<SSingleTexImpl<STex3DUncompressed> >(spTexture, pInitialData, kDesc.CPUAccessFlags, pContext, pFormatInfo);
}
}
return spTexture;
}
void glNamedBufferSubDataAsync(GLuint uBuffer, GLintptr iOffset, GLsizeiptr iSize, const GLvoid* pvData)
{
#if DXGL_PREVENT_NVIDIA_SUB_BUFFER_DATA_SYNCHRONIZATION
DXGL_TODO("TODO: Move to a per-device variable that is detected on startup. This value seems to be optimal for current NVIDIA drivers. Also experiment different values on test scenarios.");
enum
{
MAX_UPLOAD_SIZE = 256 * 1024
};
while (iSize > 0)
{
uint32 uUploadSize((uint32)min(iSize, (GLintptr)MAX_UPLOAD_SIZE));
glNamedBufferSubDataEXT(uBuffer, iOffset, iSize, pvData);
iOffset += uUploadSize;
iSize -= uUploadSize;
pvData = static_cast<const uint8*>(pvData) + uUploadSize;
}
#else
glNamedBufferSubDataEXT(uBuffer, iOffset, iSize, pvData);
#endif
}
void NamedBufferSubDataAsyncFast(CContext* pContext, CResourceName kBufferName, GLintptr iOffset, GLsizeiptr iSize, const GLvoid* pvData)
{
#if defined(glNamedBufferSubDataEXT) || !defined(USE_FAST_NAMED_APPROXIMATION)
glNamedBufferSubDataAsync(kBufferName.GetName(), iOffset, iSize, pvData);
#else
pContext->BindBuffer(kBufferName, eBB_CopyWrite);
#if DXGL_PREVENT_NVIDIA_SUB_BUFFER_DATA_SYNCHRONIZATION
DXGL_TODO("TODO: Move to a per-device variable that is detected on startup. This value seems to be optimal for current NVIDIA drivers. Also experiment different values on test scenarios.");
enum
{
MAX_UPLOAD_SIZE = 256 * 1024
};
while (iSize > 0)
{
uint32 uUploadSize((uint32)min(iSize, (GLintptr)MAX_UPLOAD_SIZE));
glBufferSubData(GL_COPY_WRITE_BUFFER, iOffset, iSize, pvData);
iOffset += uUploadSize;
iSize -= uUploadSize;
pvData = static_cast<const uint8*>(pvData) + uUploadSize;
}
#else
glBufferSubData(GL_COPY_WRITE_BUFFER, iOffset, iSize, pvData);
#endif
#endif
}
struct SDefaultBufferImpl
{
static void UpdateBufferSubresource(SResource* pResource, uint32 uSubresource, const D3D11_BOX* pDstBox, const void* pSrcData, uint32, uint32, CContext* pContext)
{
DXGL_SCOPED_PROFILE("SDefaultBufferImpl::UpdateBufferSubresource")
SBuffer * pBuffer(static_cast<SBuffer*>(pResource));
pBuffer->m_kCreationFence.IssueWait(pContext);
assert(uSubresource == 0);
if (pDstBox != NULL)
{
NamedBufferSubDataAsyncFast(pContext, pBuffer->m_kName, pDstBox->left, pDstBox->right - pDstBox->left, pSrcData);
}
else
{
NamedBufferSubDataAsyncFast(pContext, pBuffer->m_kName, 0, pBuffer->m_uSize, pSrcData);
}
}
};
struct SDynamicBufferImpl
{
static bool MapBufferRange(SBuffer* pBuffer, size_t uOffset, size_t uSize, D3D11_MAP eMapType, uint32 uMapFlags, D3D11_MAPPED_SUBRESOURCE* pMappedResource, CContext* pContext)
{
DXGL_SCOPED_PROFILE("SDynamicBufferImpl::MapBufferRange")
pBuffer->m_kCreationFence.IssueWait(pContext);
#if DXGL_SUPPORT_APITRACE
pMappedResource->pData = pBuffer->m_kDynamicCopy.m_pData + uOffset;
pBuffer->m_kDynamicCopy.ResetDirtyRegion();
#else
#if DXGL_SUPPORT_BUFFER_STORAGE
if (uMapFlags & (D3D11_MAP_FLAG_DXGL_COHERENT | D3D11_MAP_FLAG_DXGL_PERSISTENT))
{
if (!pContext->GetDevice()->IsFeatureSupported(eF_BufferStorage))
{
DXGL_ERROR("Cannot map buffer with persistent/coherent access since buffer storage is not supported");
return false;
}
pBuffer->m_bMapped = false;
GLbitfield uAccess(GL_MAP_WRITE_BIT);
if (uMapFlags & D3D11_MAP_FLAG_DXGL_COHERENT)
{
uAccess |= GL_MAP_COHERENT_BIT;
}
if (uMapFlags & D3D11_MAP_FLAG_DXGL_PERSISTENT)
{
uAccess |= GL_MAP_PERSISTENT_BIT;
}
pMappedResource->pData = pContext->MapNamedBufferRangeFast(pBuffer->m_kName, (GLintptr)uOffset, (GLsizeiptr)uSize, uAccess);
}
else
#endif //DXGL_SUPPORT_BUFFER_STORAGE
if (eMapType == D3D11_MAP_WRITE_NO_OVERWRITE)
{
pBuffer->m_bMapped = true;
pMappedResource->pData = pContext->MapNamedBufferRangeFast(pBuffer->m_kName, (GLintptr)uOffset, (GLsizeiptr)uSize, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
}
else
{
// The only other possible mode for dynamic buffers is D3D11_MAP_WRITE_DISCARD
assert(eMapType == D3D11_MAP_WRITE_DISCARD);
if (SGlobalConfig::iBufferUploadMode == 2 ||
(SGlobalConfig::iBufferUploadMode == 1 && pBuffer->m_eUsage == GL_DYNAMIC_DRAW))
{
pBuffer->m_bMapped = false;
pMappedResource->pData = pBuffer->m_pSystemMemoryCopy;
pContext->NamedBufferDataFast(pBuffer->m_kName, pBuffer->m_uSize, NULL, pBuffer->m_eUsage);
}
else
{
pBuffer->m_bMapped = true;
// when GL_MAP_INVALIDATE_BUFFER_BIT is set GL_MAP_UNSYNCHRONIZED_BIT will be ignored.
// Remove GL_MAP_UNSYNCHRONIZED_BIT to reduce Qualcomm driver's debug spew
pMappedResource->pData = pContext->MapNamedBufferRangeFast(pBuffer->m_kName, (GLintptr)uOffset, (GLsizeiptr)uSize, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
}
}
#endif
pMappedResource->RowPitch = 0; // Meaningless for buffers
pMappedResource->DepthPitch = 0; // Meaningless for buffers
pBuffer->m_uMapOffset = uOffset;
pBuffer->m_uMapSize = uSize;
return true;
}
static bool MapBuffer(SResource* pResource, uint32 uSubresource, D3D11_MAP eMapType, uint32 uMapFlags, D3D11_MAPPED_SUBRESOURCE* pMappedResource, CContext* pContext)
{
DXGL_SCOPED_PROFILE("SDynamicBufferImpl::MapBuffer")
SBuffer * pBuffer(static_cast<SBuffer*>(pResource));
return MapBufferRange(pBuffer, (size_t)0, (size_t)pBuffer->m_uSize, eMapType, uMapFlags, pMappedResource, pContext);
}
static void UnmapBuffer(SResource* pResource, UINT Subresource, CContext* pContext)
{
DXGL_SCOPED_PROFILE("SDynamicBufferImpl::UnmapBuffer")
SBuffer * pBuffer(static_cast<SBuffer*>(pResource));
#if DXGL_SUPPORT_APITRACE
uint32 uOffset, uSize;
if (!pBuffer->m_kDynamicCopy.GetDirtyRegion(uOffset, uSize))
{
DXGL_WARNING("GetDirtyRegion failed - performing full buffer upload");
uOffset = 0;
uSize = pBuffer->m_uSize;
}
if (uSize > 0)
{
NamedBufferSubDataAsyncFast(pContext, pBuffer->m_kName, uOffset, uSize, pBuffer->m_kDynamicCopy.m_pData + uOffset);
}
#else
if (pBuffer->m_bMapped)
{
pContext->UnmapNamedBufferFast(pBuffer->m_kName);
pBuffer->m_bMapped = false;
}
else
{
// This was mapped with D3D11_MAP_WRITE_DISCARD - orphan the current storage and upload the system memory buffer
NamedBufferSubDataAsyncFast(pContext, pBuffer->m_kName, pBuffer->m_uMapOffset, pBuffer->m_uMapSize, pBuffer->m_pSystemMemoryCopy);
}
#endif
}
static void UpdateBufferSubresource(SResource* pResource, uint32 uSubresource, const D3D11_BOX* pDstBox, const void* pSrcData, uint32, uint32, CContext* pContext)
{
DXGL_SCOPED_PROFILE("SDynamicBufferImpl::UpdateBufferSubresource")
SBuffer * pBuffer(static_cast<SBuffer*>(pResource));
pBuffer->m_kCreationFence.IssueWait(pContext);
assert(uSubresource == 0);
uint32 uDstOffset, uDstSize;
if (pDstBox != NULL)
{
uDstOffset = pDstBox->left;
uDstSize = pDstBox->right - pDstBox->left;
}
else
{
uDstOffset = 0;
uDstSize = pBuffer->m_uSize;
}
NamedBufferSubDataAsyncFast(pContext, pBuffer->m_kName, uDstOffset, uDstSize, pSrcData);
cryMemcpy(pBuffer->m_pSystemMemoryCopy, static_cast<const uint8*>(pSrcData) + uDstOffset, uDstSize);
}
};
void MapBufferSystemMemoryRange(SBuffer* pBuffer, uint32 uOffset, D3D11_MAPPED_SUBRESOURCE* pMappedResource)
{
pMappedResource->pData = pBuffer->m_pSystemMemoryCopy + uOffset;
pMappedResource->RowPitch = 0; // Meaningless for buffers
pMappedResource->DepthPitch = 0; // Meaningless for buffers
}
void UpdateBufferSystemMemory(SBuffer* pBuffer, const D3D11_BOX* pDstBox, const void* pSrcData)
{
if (pDstBox != NULL)
{
cryMemcpy(pBuffer->m_pSystemMemoryCopy + pDstBox->left, pSrcData, pDstBox->right - pDstBox->left);
}
else
{
cryMemcpy(pBuffer->m_pSystemMemoryCopy, pSrcData, pBuffer->m_uSize);
}
}
struct SStagingBufferImpl
{
static bool MapBufferRange(SBuffer* pBuffer, size_t uOffset, size_t uSize, D3D11_MAP, uint32, D3D11_MAPPED_SUBRESOURCE* pMappedResource, CContext*)
{
DXGL_SCOPED_PROFILE("SStagingBufferImpl::MapBufferRange")
MapBufferSystemMemoryRange(pBuffer, uOffset, pMappedResource);
return true;
}
static bool MapBuffer(SResource* pResource, uint32, D3D11_MAP, uint32, D3D11_MAPPED_SUBRESOURCE* pMappedResource, CContext*)
{
DXGL_SCOPED_PROFILE("SStagingBufferImpl::MapBuffer")
MapBufferSystemMemoryRange(static_cast<SBuffer*>(pResource), 0, pMappedResource);
return true;
}
static void UnmapBuffer(SResource*, UINT, CContext*)
{
}
static void UpdateBufferSubresource(SResource* pResource, uint32, const D3D11_BOX* pDstBox, const void* pSrcData, uint32, uint32, CContext*)
{
DXGL_SCOPED_PROFILE("SStagingBufferImpl::UpdateBufferSubresource")
UpdateBufferSystemMemory(static_cast<SBuffer*>(pResource), pDstBox, pSrcData);
}
};
#if DXGL_STREAMING_CONSTANT_BUFFERS
struct SStreamingBufferImpl
{
static bool MapBufferRange(SBuffer* pBuffer, size_t uOffset, size_t uSize, D3D11_MAP eMap, uint32, D3D11_MAPPED_SUBRESOURCE* pMappedResource, CContext*)
{
DXGL_SCOPED_PROFILE("SStagingBufferImpl::MapBufferRange")
MapBufferSystemMemoryRange(pBuffer, uOffset, pMappedResource);
if (eMap == D3D11_MAP_WRITE || eMap == D3D11_MAP_READ_WRITE || eMap == D3D11_MAP_WRITE_DISCARD || eMap == D3D11_MAP_WRITE_NO_OVERWRITE)
{
pBuffer->m_kContextCachesValid.SetZero();
}
return true;
}
static bool MapBuffer(SResource* pResource, uint32, D3D11_MAP eMap, uint32, D3D11_MAPPED_SUBRESOURCE* pMappedResource, CContext*)
{
DXGL_SCOPED_PROFILE("SStagingBufferImpl::MapBuffer")
SBuffer * pBuffer(static_cast<SBuffer*>(pResource));
MapBufferSystemMemoryRange(pBuffer, 0, pMappedResource);
if (eMap == D3D11_MAP_WRITE || eMap == D3D11_MAP_READ_WRITE || eMap == D3D11_MAP_WRITE_DISCARD || eMap == D3D11_MAP_WRITE_NO_OVERWRITE)
{
pBuffer->m_kContextCachesValid.SetZero();
}
return true;
}
static void UnmapBuffer(SResource*, UINT, CContext*)
{
}
static void UpdateBufferSubresource(SResource* pResource, uint32, const D3D11_BOX* pDstBox, const void* pSrcData, uint32, uint32, CContext*)
{
DXGL_SCOPED_PROFILE("SStagingBufferImpl::UpdateBufferSubresource")
SBuffer * pBuffer(static_cast<SBuffer*>(pResource));
UpdateBufferSystemMemory(pBuffer, pDstBox, pSrcData);
pBuffer->m_kContextCachesValid.SetZero();
}
};
#endif //DXGL_STREAMING_CONSTANT_BUFFERS
SBufferPtr CreateBuffer(const D3D11_BUFFER_DESC& kDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, CContext* pContext)
{
DXGL_SCOPED_PROFILE("CreateBuffer")
SBufferPtr spBuffer(new SBuffer());
spBuffer->m_uSize = kDesc.ByteWidth;
spBuffer->m_uElementSize = 0;
spBuffer->m_kBindings.SetZero();
for (UINT uBindMask = 1; uBindMask != 0; uBindMask <<= 1)
{
switch (kDesc.BindFlags & uBindMask)
{
case 0:
break;
case D3D11_BIND_VERTEX_BUFFER:
spBuffer->m_kBindings.Set(eBB_Array, true);
break;
case D3D11_BIND_INDEX_BUFFER:
spBuffer->m_kBindings.Set(eBB_ElementArray, true);
break;
case D3D11_BIND_CONSTANT_BUFFER:
spBuffer->m_kBindings.Set(eBB_UniformBuffer, true);
break;
case D3D11_BIND_SHADER_RESOURCE:
case D3D11_BIND_UNORDERED_ACCESS:
if ((kDesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) != 0)
{
spBuffer->m_uElementSize = kDesc.StructureByteStride;
#if DXGL_SUPPORT_SHADER_STORAGE_BLOCKS
spBuffer->m_kBindings.Set(eBB_ShaderStorage, true);
#endif //DXGL_SUPPORT_SHADER_STORAGE_BLOCKS
}
break;
default:
DXGL_TODO("Support more buffer bindings");
DXGL_ERROR("Buffer binding not supported");
return NULL;
}
}
bool bVideoMemory, bAllocateSystemMemory;
GLbitfield uStorageFlags(0);
#if DXGL_STREAMING_CONSTANT_BUFFERS
if (SGlobalConfig::iStreamingConstantBuffersMode > 0 &&
(kDesc.BindFlags & D3D11_BIND_CONSTANT_BUFFER) != 0 &&
(kDesc.MiscFlags & D3D11_RESOURCE_MISC_DXGL_NO_STREAMING) == 0)
{
spBuffer->m_pfMapSubresource = &SStreamingBufferImpl::MapBuffer;
spBuffer->m_pfUnmapSubresource = &SStreamingBufferImpl::UnmapBuffer;
spBuffer->m_pfUpdateSubresource = &SStreamingBufferImpl::UpdateBufferSubresource;
spBuffer->m_pfMapBufferRange = &SStreamingBufferImpl::MapBufferRange;
spBuffer->m_bStreaming = true;
bVideoMemory = true;
bAllocateSystemMemory = true;
uStorageFlags = GL_MAP_WRITE_BIT;
switch (kDesc.Usage)
{
case D3D11_USAGE_IMMUTABLE:
spBuffer->m_eUsage = GL_STATIC_DRAW;
break;
case D3D11_USAGE_DEFAULT:
spBuffer->m_eUsage = GL_STREAM_DRAW;
break;
case D3D11_USAGE_DYNAMIC:
spBuffer->m_eUsage = GL_DYNAMIC_DRAW;
break;
default:
DXGL_ERROR("Buffer usage not supported");
return NULL;
}
}
else
{
#endif //DXGL_STREAMING_CONSTANT_BUFFERS
switch (kDesc.Usage)
{
case D3D11_USAGE_DEFAULT:
spBuffer->m_pfUpdateSubresource = &SDefaultBufferImpl::UpdateBufferSubresource;
case D3D11_USAGE_IMMUTABLE:
if ((kDesc.CPUAccessFlags & D3D11_CPU_ACCESS_WRITE) == 0)
{
spBuffer->m_eUsage = GL_STATIC_READ;
}
else if ((kDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ) == 0)
{
spBuffer->m_eUsage = GL_STATIC_DRAW;
}
else
{
spBuffer->m_eUsage = GL_STATIC_COPY;
}
bVideoMemory = true;
bAllocateSystemMemory = false;
break;
case D3D11_USAGE_DYNAMIC:
spBuffer->m_pfMapSubresource = &SDynamicBufferImpl::MapBuffer;
spBuffer->m_pfUnmapSubresource = &SDynamicBufferImpl::UnmapBuffer;
spBuffer->m_pfUpdateSubresource = &SDynamicBufferImpl::UpdateBufferSubresource;
spBuffer->m_pfMapBufferRange = &SDynamicBufferImpl::MapBufferRange;
if ((kDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ) != 0)
{
DXGL_ERROR("Cannot create a buffer with dynamic usage that is CPU readable");
return NULL;
}
if ((kDesc.BindFlags & D3D11_BIND_CONSTANT_BUFFER) != 0)
{
// Assuming that constant buffers are accessed more frequently and usually discarded on updates
spBuffer->m_eUsage = GL_DYNAMIC_DRAW;
}
else
{
spBuffer->m_eUsage = GL_STREAM_DRAW;
}
bVideoMemory = true;
#if DXGL_SUPPORT_BUFFER_STORAGE
uStorageFlags = GL_MAP_WRITE_BIT;
if (kDesc.MiscFlags & D3D11_RESOURCE_MISC_DXGL_MAP_COHERENT)
{
uStorageFlags |= GL_MAP_COHERENT_BIT;
}
if (kDesc.MiscFlags & D3D11_RESOURCE_MISC_DXGL_MAP_PERSISTENT)
{
uStorageFlags |= GL_MAP_PERSISTENT_BIT;
}
#endif //DXGL_SUPPORT_BUFFER_STORAGE
#if DXGL_SUPPORT_APITRACE
spBuffer->m_pSystemMemoryCopy = spBuffer->m_kDynamicCopy.Allocate(kDesc.ByteWidth);
spBuffer->m_bSystemMemoryCopyOwner = false;
bAllocateSystemMemory = false;
#else
bAllocateSystemMemory = true;
#endif
break;
case D3D11_USAGE_STAGING:
spBuffer->m_pfMapSubresource = &SStagingBufferImpl::MapBuffer;
spBuffer->m_pfUnmapSubresource = &SStagingBufferImpl::UnmapBuffer;
spBuffer->m_pfUpdateSubresource = &SStagingBufferImpl::UpdateBufferSubresource;
spBuffer->m_pfMapBufferRange = &SStagingBufferImpl::MapBufferRange;
spBuffer->m_eUsage = GL_NONE;
bVideoMemory = false;
bAllocateSystemMemory = true;
break;
default:
DXGL_ERROR("Buffer usage not supported");
return NULL;
}
#if DXGL_STREAMING_CONSTANT_BUFFERS
}
#endif //DXGL_STREAMING_CONSTANT_BUFFERS
if (bVideoMemory)
{
GLuint uName;
glGenBuffers(1, &uName);
spBuffer->m_kName = pContext->GetDevice()->GetBufferNamePool().Create(uName);
DXGL_TODO("Handle all required conversions");
const GLvoid* pData(pInitialData == NULL ? NULL : pInitialData->pSysMem);
#if DXGL_SUPPORT_BUFFER_STORAGE
if ((uStorageFlags & (GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT)))
{
if (pContext->GetDevice()->IsFeatureSupported(eF_BufferStorage))
{
glNamedBufferStorageEXT(uName, kDesc.ByteWidth, pData, uStorageFlags);
}
else
{
DXGL_ERROR("Cannot create a persistent/coherent-mappable buffer since buffer storage is not supported");
return NULL;
}
}
else
#endif //DXGL_SUPPORT_BUFFER_STORAGE
{
glNamedBufferDataEXT(uName, kDesc.ByteWidth, pData, spBuffer->m_eUsage);
}
spBuffer->m_kCreationFence.IssueFence(pContext->GetDevice());
}
if (bAllocateSystemMemory)
{
spBuffer->m_pSystemMemoryCopy = static_cast<uint8*>(Memalign(kDesc.ByteWidth, MIN_MAPPED_RESOURCE_ALIGNMENT));
}
if (spBuffer->m_pSystemMemoryCopy != NULL && pInitialData != NULL)
{
cryMemcpy(spBuffer->m_pSystemMemoryCopy, pInitialData->pSysMem, kDesc.ByteWidth);
}
return spBuffer;
}
SQueryPtr CreateQuery(const D3D11_QUERY_DESC& kDesc, CContext*)
{
DXGL_SCOPED_PROFILE("CreateQuery")
SQueryPtr spQuery(NULL);
switch (kDesc.Query)
{
case D3D11_QUERY_OCCLUSION:
{
SOcclusionQuery* pOcclusionQuery(new SOcclusionQuery());
spQuery = pOcclusionQuery;
glGenQueries(1, &pOcclusionQuery->m_uName);
}
break;
case D3D11_QUERY_EVENT:
spQuery = new SFenceSync();
break;
#if DXGL_SUPPORT_TIMER_QUERIES
case D3D11_QUERY_TIMESTAMP:
spQuery = new STimestampQuery();
break;
case D3D11_QUERY_TIMESTAMP_DISJOINT:
spQuery = new STimestampDisjointQuery();
break;
#endif //DXGL_SUPPORT_TIMER_QUERIES
default:
DXGL_NOT_IMPLEMENTED
break;
}
return spQuery;
}
SDefaultFrameBufferTexturePtr CreateBackBufferTexture(const D3D11_TEXTURE2D_DESC& kDesc)
{
DXGL_SCOPED_PROFILE("CreateBackBufferTexture")
EGIFormat eGIFormat(GetGIFormat(kDesc.Format));
if (eGIFormat == eGIF_NUM)
{
return NULL;
}
return new SDefaultFrameBufferTexture(kDesc.Width, kDesc.Height, eGIFormat, GL_COLOR_BUFFER_BIT);
}
typedef void (* CopyTextureBoxFunc)(STexture*, STexPos, STexSubresourceID, STexture*, STexPos, STexSubresourceID, STexSize, CContext*);
void CopyVideoTextureBoxWithCopyImage(
STexture* pDstTexture, STexPos kDstPos, STexSubresourceID kDstSubID,
STexture* pSrcTexture, STexPos kSrcPos, STexSubresourceID kSrcSubID,
STexSize kBoxSize, CContext* pContext)
{
glCopyImageSubData(
pSrcTexture->m_kCopyImageView.GetName(), pSrcTexture->m_eCopyImageTarget, kSrcSubID.m_iMipLevel, kSrcPos.x, kSrcPos.y, kSrcPos.z + kSrcSubID.m_uElement,
pDstTexture->m_kCopyImageView.GetName(), pDstTexture->m_eCopyImageTarget, kDstSubID.m_iMipLevel, kDstPos.x, kDstPos.y, kDstPos.z + kDstSubID.m_uElement,
kBoxSize.x, kBoxSize.y, kBoxSize.z);
}
void CopyVideoTextureBoxWithBlitFrameBuffer(
STexture* pDstTexture, STexPos kDstPos, STexSubresourceID kDstSubID,
STexture* pSrcTexture, STexPos kSrcPos, STexSubresourceID kSrcSubID,
STexSize kBoxSize, CContext* pContext)
{
SOutputMergerTextureViewPtr spSrcView(GetCopyOutputMergerView(pSrcTexture, kSrcSubID, pContext, GetGIFormatInfo(pSrcTexture->m_eFormat)));
SOutputMergerTextureViewPtr spDstView(GetCopyOutputMergerView(pDstTexture, kDstSubID, pContext, GetGIFormatInfo(pDstTexture->m_eFormat)));
if (!pContext->BlitOutputMergerView(
spSrcView, spDstView,
kSrcPos.x, kSrcPos.y, kSrcPos.x + kBoxSize.x, kSrcPos.y + kBoxSize.y,
kDstPos.x, kDstPos.y, kDstPos.x + kBoxSize.x, kDstPos.y + kBoxSize.y,
GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
GL_NEAREST))
{
DXGL_ERROR("Error copying texture box with BlitFrameBuffer");
}
}
void CopyVideoTextureBoxWithPixelBuffer(
STexture* pDstTexture, STexPos kDstPos, STexSubresourceID kDstSubID,
STexture* pSrcTexture, STexPos kSrcPos, STexSubresourceID kSrcSubID,
STexSize kBoxSize, CContext* pContext)
{
SMappedSubTexture kDataLocation;
uint32 uPackedSize(pSrcTexture->m_pfLocatePackedDataFunc(pSrcTexture, kSrcSubID, kSrcPos, kDataLocation));
const CResourceName& kCopyPixelBuffer(pContext->GetCopyPixelBuffer());
glNamedBufferDataEXT(kCopyPixelBuffer.GetName(), uPackedSize, NULL, GL_STREAM_COPY);
pContext->BindBuffer(kCopyPixelBuffer, eBB_PixelPack);
pSrcTexture->m_pfPackData(pSrcTexture, kSrcSubID, kSrcPos, kBoxSize, kDataLocation, pContext);
pContext->BindBuffer(CResourceName(), eBB_PixelPack);
pContext->BindBuffer(kCopyPixelBuffer, eBB_PixelUnpack);
pDstTexture->m_pfUnpackData(pDstTexture, kDstSubID, kDstPos, kBoxSize, kDataLocation, pContext);
pContext->BindBuffer(CResourceName(), eBB_PixelUnpack);
}
#if DXGL_USE_PBO_FOR_STAGING_TEXTURES
void CopyVideoToSystemTextureBox(
STexture* pDstTexture, STexPos kDstPos, STexSubresourceID kDstSubID,
STexture* pSrcTexture, STexPos kSrcPos, STexSubresourceID kSrcSubID,
STexSize kBoxSize, CContext* pContext)
{
uint32 uDstSubResource(D3D11CalcSubresource(kDstSubID.m_iMipLevel, kDstSubID.m_uElement, pDstTexture->m_uNumMipLevels));
if (pContext->BindBuffer(pDstTexture->m_akPixelBuffers[uDstSubResource], eBB_PixelPack) == 0)
{
return;
}
SMappedSubTexture kDataLocation;
pDstTexture->m_pfLocatePackedDataFunc(pDstTexture, kDstSubID, kDstPos, kDataLocation);
pSrcTexture->m_pfPackData(pSrcTexture, kSrcSubID, kSrcPos, kBoxSize, kDataLocation, pContext);
pContext->BindBuffer(CResourceName(), eBB_PixelPack);
}
void CopySystemToVideoTextureBox(
STexture* pDstTexture, STexPos kDstPos, STexSubresourceID kDstSubID,
STexture* pSrcTexture, STexPos kSrcPos, STexSubresourceID kSrcSubID,
STexSize kBoxSize, CContext* pContext)
{
uint32 uSrcSubResource(D3D11CalcSubresource(kSrcSubID.m_iMipLevel, kSrcSubID.m_uElement, pSrcTexture->m_uNumMipLevels));
if (!pSrcTexture->m_akPixelBuffers)
{
DXGL_WARNING("Error - NULL PBO in CopySystemToVideoTextureBox");
return;
}
if (pContext->BindBuffer(pSrcTexture->m_akPixelBuffers[uSrcSubResource], eBB_PixelUnpack) == 0)
{
return;
}
SMappedSubTexture kDataLocation;
pSrcTexture->m_pfLocatePackedDataFunc(pSrcTexture, kSrcSubID, kSrcPos, kDataLocation);
pDstTexture->m_pfUnpackData(pDstTexture, kDstSubID, kDstPos, kBoxSize, kDataLocation, pContext);
pContext->BindBuffer(CResourceName(), eBB_PixelUnpack);
}
#endif //DXGL_USE_PBO_FOR_STAGING_TEXTURES
void CopySystemTextureBox(
STexture* pDstTexture, STexPos kDstPos, STexSubresourceID kDstSubID,
STexture* pSrcTexture, STexPos kSrcPos, STexSubresourceID kSrcSubID,
STexSize kBoxSize, CContext* pContext)
{
UINT uDstSubresource(D3D11CalcSubresource(kDstSubID.m_iMipLevel, kDstSubID.m_uElement, pDstTexture->m_uNumMipLevels));
UINT uSrcSubresource(D3D11CalcSubresource(kSrcSubID.m_iMipLevel, kSrcSubID.m_uElement, pSrcTexture->m_uNumMipLevels));
D3D11_BOX kDstBox;
kDstBox.left = kDstPos.x;
kDstBox.top = kDstPos.y;
kDstBox.front = kDstPos.z;
kDstBox.right = kDstPos.x + kBoxSize.x;
kDstBox.bottom = kDstPos.y + kBoxSize.y;
kDstBox.back = kDstPos.z + kBoxSize.z;
D3D11_MAPPED_SUBRESOURCE kSrcMapped;
pSrcTexture->m_pfMapSubresource(pSrcTexture, uSrcSubresource, D3D11_MAP_READ, 0, &kSrcMapped, pContext);
pDstTexture->m_pfUpdateSubresource(pDstTexture, uDstSubresource, &kDstBox, kSrcMapped.pData, kSrcMapped.RowPitch, kSrcMapped.DepthPitch, pContext);
pSrcTexture->m_pfUnmapSubresource(pSrcTexture, uSrcSubresource, pContext);
}
template <CopyTextureBoxFunc pfCopyTextureBox>
void CopyTextureImpl(STexture* pDstTexture, STexture* pSrcTexture, CContext* pContext)
{
DXGL_TODO("Check if there's a better way to do this");
STexSubresourceID kSubID;
for (kSubID.m_iMipLevel = 0; kSubID.m_iMipLevel < (GLint)pDstTexture->m_uNumMipLevels; ++kSubID.m_iMipLevel)
{
STexBox kBox;
GetTextureBox(kBox, pDstTexture, kSubID.m_iMipLevel, GetGIFormatInfo(pDstTexture->m_eFormat), true);
for (kSubID.m_uElement = 0; kSubID.m_uElement < pDstTexture->m_uNumElements; ++kSubID.m_uElement)
{
pfCopyTextureBox(
pDstTexture, kBox.m_kOffset, kSubID,
pSrcTexture, kBox.m_kOffset, kSubID,
kBox.m_kSize, pContext);
}
}
}
void CopyTexture(STexture* pDstTexture, STexture* pSrcTexture, CContext* pContext)
{
DXGL_SCOPED_PROFILE("CopyTexture")
if (pSrcTexture->m_uNumMipLevels != pDstTexture->m_uNumMipLevels ||
pSrcTexture->m_uNumElements != pDstTexture->m_uNumElements ||
pSrcTexture->m_iWidth != pDstTexture->m_iWidth ||
pSrcTexture->m_iHeight != pDstTexture->m_iHeight ||
pSrcTexture->m_iDepth != pDstTexture->m_iDepth)
{
DXGL_ERROR("Source and destination textures to copy don't match");
return;
}
pDstTexture->m_kCreationFence.IssueWait(pContext);
pSrcTexture->m_kCreationFence.IssueWait(pContext);
// Handle the default framebuffer texture case
DXGL_TODO("This is not the most efficient way to copy from or to the default frame buffer - we are forcing the copy texture to exist. Use glReadPixels and glBlitFrameBuffer when possible.")
pDstTexture->OnCopyWrite(pContext);
pSrcTexture->OnCopyRead(pContext);
if (pDstTexture->m_kName.IsValid() && pSrcTexture->m_kName.IsValid())
{
if (pContext->GetDevice()->IsFeatureSupported(eF_CopyImage))
{
CopyTextureImpl<CopyVideoTextureBoxWithCopyImage>(pDstTexture, pSrcTexture, pContext);
}
else
{
const SGIFormatInfo* pSrcFormatInfo(GetGIFormatInfo(pSrcTexture->m_eFormat));
if (pSrcFormatInfo->m_pUncompressed != NULL && pSrcTexture->m_iDepth == 1)
{
const SGIFormatInfo* pDstFormatInfo(GetGIFormatInfo(pDstTexture->m_eFormat));
if (pDstFormatInfo->m_pUncompressed != NULL && pDstTexture->m_iDepth == 1)
{
CopyTextureImpl<CopyVideoTextureBoxWithBlitFrameBuffer>(pDstTexture, pSrcTexture, pContext);
}
else
{
CopyTextureImpl<CopyVideoTextureBoxWithPixelBuffer>(pDstTexture, pSrcTexture, pContext);
}
}
else
{
CopyTextureImpl<CopySystemTextureBox>(pDstTexture, pSrcTexture, pContext);
}
}
}
#if DXGL_USE_PBO_FOR_STAGING_TEXTURES
else if (pDstTexture->m_kName.IsValid())
{
CopyTextureImpl<CopySystemToVideoTextureBox>(pDstTexture, pSrcTexture, pContext);
}
else if (pSrcTexture->m_kName.IsValid())
{
CopyTextureImpl<CopyVideoToSystemTextureBox>(pDstTexture, pSrcTexture, pContext);
}
#endif //DXGL_USE_PBO_FOR_STAGING_TEXTURES
else
{
CopyTextureImpl<CopySystemTextureBox>(pDstTexture, pSrcTexture, pContext);
}
}
template <CopyTextureBoxFunc pfCopyTextureBox>
void CopySubTextureImpl(
STexture* pDstTexture, uint32 uDstSubresource, uint32 uDstX, uint32 uDstY, uint32 uDstZ,
STexture* pSrcTexture, uint32 uSrcSubresource, const D3D11_BOX* pSrcBox, CContext* pContext)
{
STexSubresourceID kDstSubID;
kDstSubID.m_iMipLevel = uDstSubresource % pDstTexture->m_uNumMipLevels;
kDstSubID.m_uElement = uDstSubresource / pDstTexture->m_uNumMipLevels;
STexSubresourceID kSrcSubID;
kSrcSubID.m_iMipLevel = uSrcSubresource % pSrcTexture->m_uNumMipLevels;
kSrcSubID.m_uElement = uSrcSubresource / pSrcTexture->m_uNumMipLevels;
STexBox kSrcBox;
GetTextureBox(kSrcBox, pSrcTexture, kSrcSubID.m_iMipLevel, pSrcBox, GetGIFormatInfo(pSrcTexture->m_eFormat), true);
STexPos kDstPos(uDstX, uDstY, uDstZ);
pfCopyTextureBox(
pDstTexture, kDstPos, kDstSubID,
pSrcTexture, kSrcBox.m_kOffset, kSrcSubID,
kSrcBox.m_kSize, pContext);
}
void CopySubTexture(
STexture* pDstTexture, uint32 uDstSubresource, uint32 uDstX, uint32 uDstY, uint32 uDstZ,
STexture* pSrcTexture, uint32 uSrcSubresource, const D3D11_BOX* pSrcBox, CContext* pContext)
{
DXGL_SCOPED_PROFILE("CopySubTexture")
pDstTexture->m_kCreationFence.IssueWait(pContext);
pSrcTexture->m_kCreationFence.IssueWait(pContext);
// Handle the default framebuffer texture case
DXGL_TODO("This is not the most efficient way to copy from or to the default frame buffer - we are forcing the copy texture to exist. Use glReadPixels and glBlitFrameBuffer when possible.")
pDstTexture->OnCopyWrite(pContext);
pSrcTexture->OnCopyRead(pContext);
if (pDstTexture->m_kName.IsValid() && pSrcTexture->m_kName.IsValid())
{
if (pContext->GetDevice()->IsFeatureSupported(eF_CopyImage))
{
CopySubTextureImpl<CopyVideoTextureBoxWithCopyImage>(pDstTexture, uDstSubresource, uDstX, uDstY, uDstZ, pSrcTexture, uSrcSubresource, pSrcBox, pContext);
}
else
{
const SGIFormatInfo* pSrcFormatInfo(GetGIFormatInfo(pSrcTexture->m_eFormat));
if (pSrcFormatInfo->m_pUncompressed != NULL && pSrcTexture->m_iDepth == 1)
{
const SGIFormatInfo* pDstFormatInfo(GetGIFormatInfo(pDstTexture->m_eFormat));
if (pDstFormatInfo->m_pUncompressed != NULL && pDstTexture->m_iDepth == 1)
{
CopySubTextureImpl<CopyVideoTextureBoxWithBlitFrameBuffer>(pDstTexture, uDstSubresource, uDstX, uDstY, uDstZ, pSrcTexture, uSrcSubresource, pSrcBox, pContext);
}
else
{
CopySubTextureImpl<CopyVideoTextureBoxWithPixelBuffer>(pDstTexture, uDstSubresource, uDstX, uDstY, uDstZ, pSrcTexture, uSrcSubresource, pSrcBox, pContext);
}
}
else
{
CopySubTextureImpl<CopySystemTextureBox>(pDstTexture, uDstSubresource, uDstX, uDstY, uDstZ, pSrcTexture, uSrcSubresource, pSrcBox, pContext);
}
}
}
#if DXGL_USE_PBO_FOR_STAGING_TEXTURES
else if (pDstTexture->m_kName.IsValid())
{
CopySubTextureImpl<CopySystemToVideoTextureBox>(pDstTexture, uDstSubresource, uDstX, uDstY, uDstZ, pSrcTexture, uSrcSubresource, pSrcBox, pContext);
}
else if (pSrcTexture->m_kName.IsValid())
{
CopySubTextureImpl<CopyVideoToSystemTextureBox>(pDstTexture, uDstSubresource, uDstX, uDstY, uDstZ, pSrcTexture, uSrcSubresource, pSrcBox, pContext);
}
#endif //DXGL_USE_PBO_FOR_STAGING_TEXTURES
else
{
CopySubTextureImpl<CopySystemTextureBox>(pDstTexture, uDstSubresource, uDstX, uDstY, uDstZ, pSrcTexture, uSrcSubresource, pSrcBox, pContext);
}
}
void CopySubBufferInternal(SBuffer* pDstBuffer, SBuffer* pSrcBuffer, uint32 uDstOffset, uint32 uSrcOffset, uint32 uSize)
{
if (pSrcBuffer->m_pSystemMemoryCopy != NULL && pDstBuffer->m_pSystemMemoryCopy != NULL)
{
cryMemcpy(pDstBuffer->m_pSystemMemoryCopy + uDstOffset, pSrcBuffer->m_pSystemMemoryCopy + uSrcOffset, uSize);
}
if (pDstBuffer->m_kName.IsValid())
{
if (pSrcBuffer->m_kName.IsValid())
{
glNamedCopyBufferSubDataEXT(pSrcBuffer->m_kName.GetName(), pDstBuffer->m_kName.GetName(), uSrcOffset, uDstOffset, uSize);
}
else
{
glNamedBufferSubDataAsync(pDstBuffer->m_kName.GetName(), uDstOffset, uSize, pSrcBuffer->m_pSystemMemoryCopy + uSrcOffset);
}
}
else if (pSrcBuffer->m_kName.IsValid() && pSrcBuffer->m_pSystemMemoryCopy == NULL)
{
#if DXGLES
GLvoid* pvData(glMapNamedBufferRangeEXT(pSrcBuffer->m_kName.GetName(), uSrcOffset, uSize, GL_MAP_READ_BIT));
if (pvData == NULL)
{
DXGL_ERROR("CopySubBufferInternal - could not map buffer for reading");
return;
}
memcpy(pDstBuffer->m_pSystemMemoryCopy + uDstOffset, pvData, uSize);
glUnmapBuffer(pSrcBuffer->m_kName.GetName());
#else
glGetNamedBufferSubDataEXT(pSrcBuffer->m_kName.GetName(), uSrcOffset, uSize, pDstBuffer->m_pSystemMemoryCopy + uDstOffset);
#endif
}
}
void CopyBuffer(SBuffer* pDstBuffer, SBuffer* pSrcBuffer, CContext* pContext)
{
DXGL_SCOPED_PROFILE("CopyBuffer")
if (pSrcBuffer->m_uSize != pDstBuffer->m_uSize)
{
DXGL_ERROR("Source and destination buffers to copy don't match");
return;
}
pDstBuffer->m_kCreationFence.IssueWait(pContext);
pSrcBuffer->m_kCreationFence.IssueWait(pContext);
CopySubBufferInternal(pDstBuffer, pSrcBuffer, 0, 0, pSrcBuffer->m_uSize);
}
void CopySubBuffer(
SBuffer* pDstBuffer, uint32 uDstSubresource, uint32 uDstX, uint32, uint32,
SBuffer* pSrcBuffer, uint32 uSrcSubresource, const D3D11_BOX* pSrcBox, CContext* pContext)
{
DXGL_SCOPED_PROFILE("CopySubBuffer")
uint32 uSrcBegin, uSrcEnd;
if (pSrcBox != NULL)
{
uSrcBegin = pSrcBox->left;
uSrcEnd = pSrcBox->right;
}
else
{
uSrcBegin = 0;
uSrcEnd = pSrcBuffer->m_uSize;
}
uint32 uSize(uSrcEnd - uSrcBegin);
if (uSrcBegin > pSrcBuffer->m_uSize ||
uSrcEnd > pSrcBuffer->m_uSize ||
uDstX + uSize > pDstBuffer->m_uSize)
{
DXGL_ERROR("Source or destination range out of bounds");
return;
}
pDstBuffer->m_kCreationFence.IssueWait(pContext);
pSrcBuffer->m_kCreationFence.IssueWait(pContext);
CopySubBufferInternal(pDstBuffer, pSrcBuffer, uDstX, uSrcBegin, uSize);
}
GLenum GetBufferBindingTarget(EBufferBinding eBinding)
{
switch (eBinding)
{
case eBB_Array:
return GL_ARRAY_BUFFER;
case eBB_CopyRead:
return GL_COPY_READ_BUFFER;
case eBB_CopyWrite:
return GL_COPY_WRITE_BUFFER;
case eBB_ElementArray:
return GL_ELEMENT_ARRAY_BUFFER;
case eBB_PixelPack:
return GL_PIXEL_PACK_BUFFER;
case eBB_PixelUnpack:
return GL_PIXEL_UNPACK_BUFFER;
case eBB_TransformFeedback:
return GL_TRANSFORM_FEEDBACK_BUFFER;
case eBB_UniformBuffer:
return GL_UNIFORM_BUFFER;
#if DXGL_SUPPORT_DRAW_INDIRECT
case eBB_DrawIndirect:
return GL_DRAW_INDIRECT_BUFFER;
#endif //DXGL_SUPPORT_DRAW_INDIRECT
#if DXGL_SUPPORT_ATOMIC_COUNTERS
case eBB_AtomicCounter:
return GL_ATOMIC_COUNTER_BUFFER;
#endif //DXGL_SUPPORT_ATOMIC_COUNTERS
#if DXGL_SUPPORT_DISPATCH_INDIRECT
case eBB_DispachIndirect:
return GL_DISPATCH_INDIRECT_BUFFER;
#endif //DXGL_SUPPORT_DISPATCH_INDIRECT
#if DXGL_SUPPORT_SHADER_STORAGE_BLOCKS
case eBB_ShaderStorage:
return GL_SHADER_STORAGE_BUFFER;
#endif //DXGL_SUPPORT_SHADER_STORAGE_BLOCKS
}
DXGL_ERROR("Invalid buffer binding");
return 0;
}
GLenum GetBufferBindingPoint(EBufferBinding eBinding)
{
switch (eBinding)
{
case eBB_Array:
return GL_ARRAY_BUFFER_BINDING;
case eBB_CopyRead:
return GL_COPY_READ_BUFFER_BINDING;
case eBB_CopyWrite:
return GL_COPY_WRITE_BUFFER_BINDING;
case eBB_ElementArray:
return GL_ELEMENT_ARRAY_BUFFER_BINDING;
case eBB_PixelPack:
return GL_PIXEL_PACK_BUFFER_BINDING;
case eBB_PixelUnpack:
return GL_PIXEL_UNPACK_BUFFER_BINDING;
case eBB_TransformFeedback:
return GL_TRANSFORM_FEEDBACK_BUFFER_BINDING;
case eBB_UniformBuffer:
return GL_UNIFORM_BUFFER_BINDING;
#if DXGL_SUPPORT_DRAW_INDIRECT
case eBB_DrawIndirect:
return GL_DRAW_INDIRECT_BUFFER_BINDING;
#endif //DXGL_SUPPORT_DRAW_INDIRECT
#if DXGL_SUPPORT_ATOMIC_COUNTERS
case eBB_AtomicCounter:
return GL_ATOMIC_COUNTER_BUFFER_BINDING;
#endif //DXGL_SUPPORT_ATOMIC_COUNTERS
#if DXGL_SUPPORT_DISPATCH_INDIRECT
case eBB_DispachIndirect:
return GL_DISPATCH_INDIRECT_BUFFER_BINDING;
#endif //DXGL_SUPPORT_DISPATCH_INDIRECT
#if DXGL_SUPPORT_SHADER_STORAGE_BLOCKS
case eBB_ShaderStorage:
return GL_SHADER_STORAGE_BUFFER_BINDING;
#endif //DXGL_SUPPORT_SHADER_STORAGE_BLOCKS
}
DXGL_ERROR("Invalid buffer binding");
return 0;
}
}