/* * 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 view related functions #include #include "GLView.hpp" #include "GLDevice.hpp" namespace NCryOpenGL { CResourceName CreateTextureView(STexture* pTexture, const SGIFormatInfo* pFormatInfo, GLenum eTarget, GLuint uMinMipLevel, GLuint uNumMipLevels, GLuint uMinLayer, GLuint uNumLayers, CContext* pContext) { #if DXGL_SUPPORT_TEXTURE_VIEWS if (pContext->GetDevice()->IsFeatureSupported(eF_TextureViews)) { GLint iInternalFormat; if (pFormatInfo->m_eTypelessConversion != eGIFC_TEXTURE_VIEW) { // This can happen if lazy texture view creation is disabled or two views with different modifiers // are bound at the same time (for example one view as DEPTH_TO_RED, one as STENCIL_TO_GREEN). // In this case create a view with same format as the original texture, so that it will have its own // separate format modifier. iInternalFormat = GetGIFormatInfo(pTexture->m_eFormat)->m_pTexture->m_iInternalFormat; } else { if (pFormatInfo->m_pTexture == NULL) { DXGL_ERROR("Invalid format for texture view"); return CResourceName(); } iInternalFormat = pFormatInfo->m_pTexture->m_iInternalFormat; } GLuint uView; glGenTextures(1, &uView); glTextureViewEXT(uView, eTarget, pTexture->m_kName.GetName(), iInternalFormat, uMinMipLevel, uNumMipLevels, uMinLayer, uNumLayers); return pContext->GetDevice()->GetTextureNamePool().Create(uView); } else #endif { DXGL_ERROR("glTextureView not supported - cannot create the requested unique view for the texture"); return CResourceName(); } } CResourceName CreateTextureBuffer(SBuffer* pBuffer, const SGIFormatInfo* pFormatInfo, uint32 uFirstElement, uint32 uNumElements, CContext* pContext) { #if DXGL_SUPPORT_TEXTURE_BUFFERS uint32 uElementSize(pFormatInfo->m_pTexture->m_uNumBlockBytes); uint32 uViewSize(uNumElements * uElementSize); bool bEntireBuffer(uFirstElement == 0 && uViewSize == pBuffer->m_uSize); #if !defined(glTexBufferRange) if (!bEntireBuffer) { DXGL_ERROR("glTexBufferRange is not supported - can't create an arbitrary texture buffer"); return CResourceName(); } #endif //!defined(glTexBufferRange) GLuint uView; glGenTextures(1, &uView); #if defined(glTexBufferRange) if (!bEntireBuffer) { glTextureBufferRangeEXT(uView, GL_TEXTURE_BUFFER, pFormatInfo->m_pTexture->m_iInternalFormat, pBuffer->m_kName.GetName(), uFirstElement * uElementSize, uViewSize); } else #endif //defined(glTexBufferRange) glTextureBufferEXT(uView, GL_TEXTURE_BUFFER, pFormatInfo->m_pTexture->m_iInternalFormat, pBuffer->m_kName.GetName()); return pContext->GetDevice()->GetTextureNamePool().Create(uView); #else DXGL_ERROR("Buffer shader resource views are not supported on this configuration"); return CResourceName(); #endif } SShaderView::SShaderView(Type eType) : m_eType(eType) { } SShaderView::~SShaderView() { } SShaderBufferView::SShaderBufferView(const SBufferRange& kRange) : SShaderView(eSVT_Buffer) , m_kRange(kRange) { } SShaderBufferView::~SShaderBufferView() { } void SShaderBufferView::Init(SBuffer* pBuffer, CContext* pContext) { pBuffer->m_kCreationFence.IssueWait(pContext); m_kName = pBuffer->m_kName; m_kCreationFence.IssueFence(pContext->GetDevice()); } SShaderTextureBasedView::SShaderTextureBasedView(Type eType) : SShaderView(eType) , m_bTextureOwned(false) { } SShaderTextureBasedView::~SShaderTextureBasedView() { if (m_bTextureOwned) { GLuint uTextureName(m_kName.GetName()); glDeleteTextures(1, &uTextureName); } } bool SShaderTextureBasedView::BindTextureUnit(SSamplerState* pSamplerState, STextureUnitContext& kContext, CContext* pContext, const STextureUnitCache& kCurrentUnitCache) { DXGL_ERROR("Cannot bind this type of texture based view to a texture unit"); return false; } bool SShaderTextureBasedView::GenerateMipmaps(CContext*) { DXGL_ERROR("Cannot create mipmaps from this type of texture based view"); return false; } SShaderTextureBufferView::SShaderTextureBufferView(const SShaderTextureBufferViewConfiguration& kConfiguration) : SShaderTextureBasedView(eSVT_Texture) , m_pBuffer(NULL) , m_kConfiguration(kConfiguration) , m_pNextView(NULL) { } SShaderTextureBufferView::~SShaderTextureBufferView() { if (m_pBuffer != NULL) { SShaderTextureBufferView** pLink = &m_pBuffer->m_pTextureBuffersHead; while (*pLink != NULL) { if (*pLink == this) { *pLink = m_pNextView; break; } pLink = &((*pLink)->m_pNextView); } } } bool SShaderTextureBufferView::Init(SBuffer* pBuffer, CContext* pContext) { const SGIFormatInfo* pFormatInfo; if ((pFormatInfo = GetGIFormatInfo(m_kConfiguration.m_eFormat)) == NULL || pFormatInfo->m_pTexture == NULL) { DXGL_ERROR("Invalid format for buffer view"); return false; } pBuffer->m_kCreationFence.IssueWait(pContext); CResourceName kTextureBufferName(CreateTextureBuffer(pBuffer, pFormatInfo, m_kConfiguration.m_uFirstElement, m_kConfiguration.m_uNumElements, pContext)); if (!kTextureBufferName.IsValid()) { return false; } m_kName = kTextureBufferName; m_kCreationFence.IssueFence(pContext->GetDevice()); m_bTextureOwned = true; m_pBuffer = pBuffer; m_pNextView = pBuffer->m_pTextureBuffersHead; pBuffer->m_pTextureBuffersHead = this; return true; } bool SShaderTextureBufferView::BindTextureUnit(SSamplerState* pSamplerState, STextureUnitContext& kContext, CContext* pContext, const STextureUnitCache& kCurrentUnitCache) { kContext.m_kCurrentUnitState.m_kTextureName = m_kName; kContext.m_kCurrentUnitState.m_uSampler = pSamplerState->m_uSamplerObjectNoMip; #if DXGLES // OpenGL ES does not have texture buffers DXGL_TODO("Find alternatives for TEXTURE BUFFER") kContext.m_kCurrentUnitState.m_eTextureTarget = GL_INVALID_ENUM; #else kContext.m_kCurrentUnitState.m_eTextureTarget = GL_TEXTURE_BUFFER; #endif assert(m_kName.IsValid()); return true; } SShaderTextureView::SShaderTextureView(const SShaderTextureViewConfiguration& kConfiguration) : SShaderTextureBasedView(eSVT_Texture) , m_pTexture(NULL) , m_kConfiguration(kConfiguration) , m_pNextView(NULL) { } SShaderTextureView::~SShaderTextureView() { if (m_pTexture != NULL) { SShaderTextureView** pLink = &m_pTexture->m_pShaderViewsHead; while (*pLink != NULL) { if (*pLink == this) { *pLink = m_pNextView; break; } pLink = &((*pLink)->m_pNextView); } } } bool SShaderTextureView::Init(STexture* pTexture, CContext* pContext) { const SGIFormatInfo* pFormatInfo; if (m_kConfiguration.m_eFormat == eGIF_NUM || (pFormatInfo = GetGIFormatInfo(m_kConfiguration.m_eFormat)) == NULL) { DXGL_ERROR("Invalid format for shader resource view"); return false; } m_kViewState.m_iBaseMipLevel = (GLint)m_kConfiguration.m_uMinMipLevel; m_kViewState.m_iMaxMipLevel = (GLint)(m_kConfiguration.m_uMinMipLevel + m_kConfiguration.m_uNumMipLevels - 1); m_kViewState.m_uSwizzleMask = pFormatInfo->m_uDXGISwizzleMask; #if DXGL_SUPPORT_STENCIL_TEXTURES m_kViewState.m_iDepthStencilTextureMode = 0; #endif //DXGL_SUPPORT_STENCIL_TEXTURES m_pTexture = pTexture; m_bFormatRequiresUniqueView = false; if (m_kConfiguration.m_eFormat != pTexture->m_eFormat) { if (pFormatInfo->m_eTypelessFormat != pTexture->m_eFormat) { DXGL_ERROR("Shader resource view format is not compatible with texture format"); return false; } switch (pFormatInfo->m_eTypelessConversion) { case eGIFC_DEPTH_TO_RED: #if DXGL_SUPPORT_STENCIL_TEXTURES if (pContext->GetDevice()->IsFeatureSupported(eF_StencilTextures)) { m_kViewState.m_iDepthStencilTextureMode = GL_DEPTH_COMPONENT; } #endif //DXGL_SUPPORT_STENCIL_TEXTURES break; case eGIFC_STENCIL_TO_RED: #if DXGL_SUPPORT_STENCIL_TEXTURES if (pContext->GetDevice()->IsFeatureSupported(eF_StencilTextures)) { m_kViewState.m_iDepthStencilTextureMode = GL_STENCIL_INDEX; } else #endif //DXGL_SUPPORT_STENCIL_TEXTURES { DXGL_ERROR("Stencil texturing not supported - cannot create shader resource view for stencil format"); return false; } break; case eGIFC_TEXTURE_VIEW: m_bFormatRequiresUniqueView = true; break; case eGIFC_UNSUPPORTED: DXGL_ERROR("Shader resource view conversion not supported for the requested format"); return false; } } if (m_kConfiguration.m_eTarget != pTexture->m_eTarget) { m_bFormatRequiresUniqueView = true; } if (m_bFormatRequiresUniqueView || m_kConfiguration.m_uMinLayer > 0 || m_kConfiguration.m_uNumLayers != pTexture->m_uNumElements) { if (!CreateUniqueView(pContext)) { return false; } } else { m_kName = pTexture->m_kName; pTexture->m_kCreationFence.IssueWait(pContext); m_kCreationFence.IssueFence(pContext->GetDevice()); m_bTextureOwned = false; } m_pNextView = pTexture->m_pShaderViewsHead; pTexture->m_pShaderViewsHead = this; return true; } bool SShaderTextureView::CreateUniqueView(CContext* pContext) { const SGIFormatInfo* pFormatInfo(GetGIFormatInfo(m_kConfiguration.m_eFormat)); m_pTexture->m_kCreationFence.IssueWait(pContext); CResourceName kUniqueView = CreateTextureView( m_pTexture, pFormatInfo, m_kConfiguration.m_eTarget, m_kConfiguration.m_uMinMipLevel, m_kConfiguration.m_uNumMipLevels, m_kConfiguration.m_uMinLayer, m_kConfiguration.m_uNumLayers, pContext); if (kUniqueView.IsValid()) { m_kName = kUniqueView; m_bTextureOwned = true; m_kViewState.ApplyFormatMode(kUniqueView.GetName(), m_kConfiguration.m_eTarget); m_kCreationFence.IssueFence(pContext->GetDevice()); return true; } return false; } bool SShaderTextureView::BindTextureUnit(SSamplerState* pSamplerState, STextureUnitContext& kContext, CContext* pContext, const STextureUnitCache& kCurrentUnitCache) { kContext.m_kCurrentUnitState.m_uSampler = m_kConfiguration.m_uNumMipLevels > 1 ? pSamplerState->m_uSamplerObjectMip : pSamplerState->m_uSamplerObjectNoMip; kContext.m_kCurrentUnitState.m_eTextureTarget = m_kConfiguration.m_eTarget; if (!m_bTextureOwned) { if (m_kConfiguration.m_eTarget == m_pTexture->m_eTarget) { if (m_pTexture->m_pBoundModifier == this) { kContext.m_kCurrentUnitState.m_kTextureName = m_pTexture->m_kName; return true; } if (m_pTexture->m_pBoundModifier == NULL || (m_pTexture->m_pBoundModifier && !m_bFormatRequiresUniqueView)) { if (m_pTexture->m_kCache != m_kViewState) { m_kViewState.Apply(m_pTexture->m_kName.GetName(), m_kConfiguration.m_eTarget, kCurrentUnitCache); m_pTexture->m_kCache = m_kViewState; } m_pTexture->m_pBoundModifier = this; kContext.m_kModifiedTextures.push_back(m_pTexture); kContext.m_kCurrentUnitState.m_kTextureName = m_pTexture->m_kName; return true; } } if (!CreateUniqueView(pContext)) { return false; } } kContext.m_kCurrentUnitState.m_kTextureName = m_kName; return true; } bool SShaderTextureView::GenerateMipmaps(CContext* pContext) { DXGL_TODO("Verify the expected behavior when the view has non-default parameters (currently ignored)") glGenerateTextureMipmapEXT(m_pTexture->m_kName.GetName(), m_kConfiguration.m_eTarget); m_kCreationFence.IssueWait(pContext); return true; } SShaderImageView::SShaderImageView(const SShaderImageViewConfiguration& kConfiguration) : SShaderTextureBasedView(eSVT_Image) , m_kConfiguration(kConfiguration) { } SShaderImageView::~SShaderImageView() { } bool SShaderImageView::Init(STexture* pTexture, CContext* pContext) { m_kName = pTexture->m_kName; pTexture->m_kCreationFence.IssueWait(pContext); m_kCreationFence.IssueFence(pContext->GetDevice()); m_bTextureOwned = false; return true; } bool SShaderImageView::Init(SShaderTextureBasedView* pTextureBufferView, CContext* pContext) { m_spAuxiliaryView = pTextureBufferView; m_kName = pTextureBufferView->m_kName; pTextureBufferView->m_kCreationFence.IssueWait(pContext); m_kCreationFence.IssueFence(pContext->GetDevice()); m_bTextureOwned = false; return true; } SOutputMergerView::SOutputMergerView(const CResourceName& kUniqueView, EGIFormat eFormat) : m_kUniqueView(kUniqueView) , m_eFormat(eFormat) { memset(m_kContextMap, 0, sizeof(m_kContextMap)); } SOutputMergerView::~SOutputMergerView() { uint32 uContext; for (uContext = 0; uContext < DXGL_ARRAY_SIZE(m_kContextMap); ++uContext) { SContextData* pContextData(m_kContextMap[uContext]); if (pContextData != NULL) { // All frame buffers with this view bound must be removed from the cache and deleted TFrameBufferRefs::iterator kFrameBufferRefIter(pContextData->m_kBoundFrameBuffers.begin()); const TFrameBufferRefs::iterator kFrameBufferRefEnd(pContextData->m_kBoundFrameBuffers.end()); while (kFrameBufferRefIter != kFrameBufferRefEnd) { SFrameBuffer* pFrameBuffer(kFrameBufferRefIter->m_spFrameBuffer); pFrameBuffer->m_pContext->RemoveFrameBuffer(pFrameBuffer, this); ++kFrameBufferRefIter; } delete pContextData; } } if (m_kUniqueView.IsValid()) { GLuint uUniqueViewName(m_kUniqueView.GetName()); glDeleteTextures(1, &uUniqueViewName); } } bool SOutputMergerView::AttachFrameBuffer(SFrameBuffer* pFrameBuffer, GLenum eAttachmentID, CContext* pContext) { SContextData* pContextData(m_kContextMap[pFrameBuffer->m_pContext->GetIndex()]); if (pContextData == NULL) { pContextData = new SContextData(); m_kContextMap[pFrameBuffer->m_pContext->GetIndex()] = pContextData; } TFrameBufferRefs::iterator kFound(std::find(pContextData->m_kBoundFrameBuffers.begin(), pContextData->m_kBoundFrameBuffers.end(), pFrameBuffer)); if (kFound == pContextData->m_kBoundFrameBuffers.end()) { pContextData->m_kBoundFrameBuffers.push_back(SFrameBufferRef(pFrameBuffer, 1)); } else { ++kFound->m_uNumBindings; } // Might need to disable PLS off 1st pContext->UpdatePlsState(true); return FrameBufferTexture(pFrameBuffer->m_kObject.m_kName.GetName(), eAttachmentID); } void SOutputMergerView::DetachFrameBuffer(SFrameBuffer* pFrameBuffer) { SContextData* pContextData(m_kContextMap[pFrameBuffer->m_pContext->GetIndex()]); if (pContextData == NULL) { DXGL_ERROR("Frame buffer context has not been registered to this output merger view"); return; } TFrameBufferRefs::iterator kFound(std::find(pContextData->m_kBoundFrameBuffers.begin(), pContextData->m_kBoundFrameBuffers.end(), pFrameBuffer)); if (kFound != pContextData->m_kBoundFrameBuffers.end()) { if (--kFound->m_uNumBindings == 0) { pContextData->m_kBoundFrameBuffers.erase(kFound); } } else { DXGL_ERROR("Could not find the frame buffer to be detached from the view"); } } bool SOutputMergerView::FrameBufferTexture(GLuint uFrameBuffer, GLenum eAttachmentID) { if (m_kUniqueView.IsValid()) { glNamedFramebufferTextureEXT(uFrameBuffer, eAttachmentID, m_kUniqueView.GetName(), 0); return true; } return false; } void SOutputMergerView::Bind(const SFrameBuffer&, CContext*) { } const GLint SOutputMergerTextureView::INVALID_LAYER = -1; SOutputMergerTextureView::SOutputMergerTextureView(STexture* pTexture, const SOutputMergerTextureViewConfiguration& kConfiguration) : SOutputMergerView(CResourceName(), kConfiguration.m_eFormat) , m_kConfiguration(kConfiguration) , m_pTexture(pTexture) { m_pNextView = pTexture->m_pOutputMergerViewsHead; pTexture->m_pOutputMergerViewsHead = this; } SOutputMergerTextureView::~SOutputMergerTextureView() { SOutputMergerTextureView*& pLink = m_pTexture->m_pOutputMergerViewsHead; while (pLink != NULL) { if (pLink == this) { pLink = m_pNextView; } else { pLink = pLink->m_pNextView; } } } bool SOutputMergerTextureView::Init(CContext* pContext) { m_iMipLevel = (GLint)m_kConfiguration.m_uMipLevel; if (m_kConfiguration.m_uMinLayer == 0 && m_kConfiguration.m_uNumLayers == m_pTexture->m_uNumElements) { m_iLayer = INVALID_LAYER; } else if (m_kConfiguration.m_uNumLayers == 1) { m_iLayer = m_kConfiguration.m_uMinLayer; } else { DXGL_NOT_IMPLEMENTED; } if (m_kConfiguration.m_eFormat != m_pTexture->m_eFormat) { const SGIFormatInfo* pFormatInfo; if (m_kConfiguration.m_eFormat == eGIF_NUM || (pFormatInfo = GetGIFormatInfo(m_kConfiguration.m_eFormat)) == NULL || pFormatInfo->m_pTexture == NULL) { DXGL_ERROR("Invalid format for output merger view"); return false; } if (pFormatInfo->m_pTexture->m_iInternalFormat == GetGIFormatInfo(m_pTexture->m_eFormat)->m_pTexture->m_iInternalFormat) { return true; } // Frame buffer attachment does not support any kind of in-place conversion - texture view is required unless no conversion is needed at all return CreateUniqueView(pFormatInfo, pContext); } return true; } bool SOutputMergerTextureView::FrameBufferTexture(GLuint uFrameBuffer, GLenum eAttachmentID) { GLuint uTexture(m_kUniqueView.IsValid() ? m_kUniqueView.GetName() : m_pTexture->m_kName.GetName()); if (m_iLayer == INVALID_LAYER) { glNamedFramebufferTextureEXT(uFrameBuffer, eAttachmentID, uTexture, m_iMipLevel); } else { glNamedFramebufferTextureLayerEXT(uFrameBuffer, eAttachmentID, uTexture, m_iMipLevel, m_iLayer); } return true; } bool SOutputMergerTextureView::CreateUniqueView(const SGIFormatInfo* pFormatInfo, CContext* pContext) { if (pFormatInfo->m_eTypelessFormat != m_pTexture->m_eFormat) { DXGL_ERROR("Output merger view format is not compatible with texture format"); return false; } m_kUniqueView = CreateTextureView(m_pTexture, pFormatInfo, m_pTexture->m_eTarget, 0, m_pTexture->m_uNumMipLevels, 0, m_pTexture->m_uNumElements, pContext); m_pTexture->m_kCreationFence.IssueWait(pContext); m_kCreationFence.IssueFence(pContext->GetDevice()); return true; } SDefaultFrameBufferOutputMergerView::SDefaultFrameBufferOutputMergerView(SDefaultFrameBufferTexture* pTexture, const SOutputMergerTextureViewConfiguration& kConfiguration) : SOutputMergerTextureView(pTexture, kConfiguration) , m_bUsesTexture(false) { } SDefaultFrameBufferOutputMergerView::~SDefaultFrameBufferOutputMergerView() { if (m_bUsesTexture) { static_cast(m_pTexture)->DecTextureRefCount(); } } bool SDefaultFrameBufferOutputMergerView::AttachFrameBuffer(SFrameBuffer* pFrameBuffer, GLenum eAttachmentID, CContext* pContext) { if (!m_bUsesTexture) { static_cast(m_pTexture)->IncTextureRefCount(pContext); m_bUsesTexture = true; } return SOutputMergerTextureView::AttachFrameBuffer(pFrameBuffer, eAttachmentID, pContext); } void SDefaultFrameBufferOutputMergerView::Bind(const SFrameBuffer& kFrameBuffer, CContext* pContext) { static_cast(m_pTexture)->OnWrite(pContext, kFrameBuffer.m_kObject.m_kName.GetName() == 0); SOutputMergerTextureView::Bind(kFrameBuffer, pContext); } bool SDefaultFrameBufferOutputMergerView::CreateUniqueView(const SGIFormatInfo* pFormatInfo, CContext* pContext) { if (!m_bUsesTexture) { static_cast(m_pTexture)->IncTextureRefCount(pContext); m_bUsesTexture = true; } return SOutputMergerTextureView::CreateUniqueView(pFormatInfo, pContext); } SDefaultFrameBufferShaderTextureView::SDefaultFrameBufferShaderTextureView(const SShaderTextureViewConfiguration& kConfiguration) : SShaderTextureView(kConfiguration) , m_bUsesTexture(false) { } SDefaultFrameBufferShaderTextureView::~SDefaultFrameBufferShaderTextureView() { } bool SDefaultFrameBufferShaderTextureView::BindTextureUnit(SSamplerState* pSamplerState, STextureUnitContext& kContext, CContext* pContext, const STextureUnitCache& kCurrentUnitCache) { SDefaultFrameBufferTexture* pDefaultFrameBufferTexture(static_cast(m_pTexture)); if (!m_bUsesTexture) { pDefaultFrameBufferTexture->IncTextureRefCount(pContext); m_bUsesTexture = true; } pDefaultFrameBufferTexture->OnRead(pContext); return SShaderTextureView::BindTextureUnit(pSamplerState, kContext, pContext, kCurrentUnitCache); } template struct SResourceViewBaseImpl { typedef ViewDesc TViewDesc; typedef View TView; typedef _smart_ptr TViewPtr; }; struct SShaderResourceViewImpl : SResourceViewBaseImpl { enum EViewDimension { DIMENSION_BUFFER = D3D11_SRV_DIMENSION_BUFFER, DIMENSION_TEXTURE1D = D3D11_SRV_DIMENSION_TEXTURE1D, DIMENSION_TEXTURE1DARRAY = D3D11_SRV_DIMENSION_TEXTURE1DARRAY, DIMENSION_TEXTURE2D = D3D11_SRV_DIMENSION_TEXTURE2D, DIMENSION_TEXTURE2DARRAY = D3D11_SRV_DIMENSION_TEXTURE2DARRAY, DIMENSION_TEXTURE2DMS = D3D11_SRV_DIMENSION_TEXTURE2DMS, DIMENSION_TEXTURE2DMSARRAY = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY, DIMENSION_TEXTURE3D = D3D11_SRV_DIMENSION_TEXTURE3D, DIMENSION_TEXTURECUBE = D3D11_SRV_DIMENSION_TEXTURECUBE, DIMENSION_TEXTURECUBEARRAY = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY, DIMENSION_BUFFEREX = D3D11_SRV_DIMENSION_BUFFEREX }; static SResourceViewBaseImpl::TViewPtr GetView(STexture* pTexture, DXGI_FORMAT eDXGIFormat, GLenum eTarget, uint32 uMinLevel, uint32 uNumLevels, uint32 uMinElement, uint32 uNumElements, CContext* pContext) { SShaderTextureViewConfiguration kConfiguration(GetGIFormat(eDXGIFormat), eTarget, uMinLevel, uNumLevels, uMinElement, uNumElements); SShaderTextureView* pExistingView(pTexture->m_pShaderViewsHead); while (pExistingView != NULL) { if (pExistingView->m_kConfiguration == kConfiguration) { return pExistingView; } pExistingView = pExistingView->m_pNextView; } return pTexture->CreateShaderResourceView(kConfiguration, pContext); } template static TViewPtr GetViewMip(STexture* pTexture, const DimDesc& kDimDesc, DXGI_FORMAT eDXGIFormat, GLenum eTarget, uint32 uMinElement, uint32 uNumElements, CContext* pContext) { uint32 uNumMipLevels(kDimDesc.MipLevels == -1 ? (pTexture->m_uNumMipLevels - kDimDesc.MostDetailedMip) : kDimDesc.MipLevels); return GetView(pTexture, eDXGIFormat, eTarget, kDimDesc.MostDetailedMip, uNumMipLevels, uMinElement, uNumElements, pContext); } template static TViewPtr GetViewLayers(STexture* pTexture, const DimDesc& kDimDesc, DXGI_FORMAT eDXGIFormat, uint32 uMinLevel, uint32 uNumLevels, GLenum eTarget, CContext* pContext) { uint32 uNumElements(kDimDesc.ArraySize == -1 ? (pTexture->m_uNumElements - kDimDesc.FirstArraySlice) : kDimDesc.ArraySize); return GetView(pTexture, eDXGIFormat, eTarget, uMinLevel, uNumLevels, kDimDesc.FirstArraySlice, uNumElements, pContext); } template static TViewPtr GetViewMipLayers(STexture* pTexture, const DimDesc& kDimDesc, DXGI_FORMAT eDXGIFormat, GLenum eTarget, CContext* pContext) { uint32 uNumElements(kDimDesc.ArraySize == -1 ? (pTexture->m_uNumElements - kDimDesc.FirstArraySlice) : kDimDesc.ArraySize); return GetViewMip(pTexture, kDimDesc, eDXGIFormat, eTarget, kDimDesc.FirstArraySlice, uNumElements, pContext); } template static TViewPtr GetView(SBuffer* pBuffer, const DimDesc& kDimDesc, DXGI_FORMAT eDXGIFormat, UINT uFlags, CContext* pContext) { return pBuffer->CreateShaderResourceView(GetGIFormat(eDXGIFormat), kDimDesc.FirstElement, kDimDesc.NumElements, uFlags, pContext); } template static TViewPtr GetViewEx(SBuffer* pBuffer, const DimDesc& kDimDesc, DXGI_FORMAT eDXGIFormat, CContext* pContext) { return GetView(pBuffer, kDimDesc, eDXGIFormat, kDimDesc.Flags, pContext); } }; struct SUnorderedAccessViewImpl : SResourceViewBaseImpl { enum EViewDimension { DIMENSION_BUFFER = D3D11_UAV_DIMENSION_BUFFER, DIMENSION_TEXTURE1D = D3D11_UAV_DIMENSION_TEXTURE1D, DIMENSION_TEXTURE1DARRAY = D3D11_UAV_DIMENSION_TEXTURE1DARRAY, DIMENSION_TEXTURE2D = D3D11_UAV_DIMENSION_TEXTURE2D, DIMENSION_TEXTURE2DARRAY = D3D11_UAV_DIMENSION_TEXTURE2DARRAY, DIMENSION_TEXTURE3D = D3D11_UAV_DIMENSION_TEXTURE3D, }; static SResourceViewBaseImpl::TViewPtr GetView(STexture* pTexture, DXGI_FORMAT eDXGIFormat, GLenum eTarget, uint32 uMipSlice, uint32 uMinElement, uint32 uNumElements, CContext* pContext) { EGIFormat eGIFormat(GetGIFormat(eDXGIFormat)); GLenum eImageFormat(GL_NONE); if (!GetImageFormat(eGIFormat, &eImageFormat)) { DXGL_ERROR("Unsupported format for unordered access view"); return NULL; } if (uMinElement == 0 && uNumElements == pTexture->m_uNumElements) { SShaderImageViewConfiguration kConfiguration(eImageFormat, (GLint)uMipSlice, -1, GL_READ_WRITE); return pTexture->CreateUnorderedAccessView(kConfiguration, pContext); } else if (uNumElements == 1) { SShaderImageViewConfiguration kConfiguration(eImageFormat, (GLint)uMipSlice, uMinElement, GL_READ_WRITE); return pTexture->CreateUnorderedAccessView(kConfiguration, pContext); } else { // Need to first create a proxy view containing only the selected layers SShaderTextureViewConfiguration kProxyConfiguration(pTexture->m_eFormat, eTarget, uMipSlice, 1, uMinElement, uNumElements); SShaderTextureViewPtr spProxyTextureView(pTexture->CreateShaderResourceView(kProxyConfiguration, pContext)); if (spProxyTextureView == NULL) { return NULL; } SShaderImageViewConfiguration kConfiguration(eImageFormat, (GLint)uMipSlice, -1, GL_READ_WRITE); SShaderImageViewPtr spImageView(new SShaderImageView(kConfiguration)); if (!spImageView->Init(spProxyTextureView, pContext)) { return NULL; } return spImageView; } } template static TViewPtr GetViewMip(STexture* pTexture, const DimDesc& kDimDesc, DXGI_FORMAT eDXGIFormat, GLenum eTarget, uint32 uMinElement, uint32 uNumElements, CContext* pContext) { return GetView(pTexture, eDXGIFormat, eTarget, kDimDesc.MipSlice, uMinElement, uNumElements, pContext); } template static TViewPtr GetViewLayers(STexture* pTexture, const DimDesc& kDimDesc, DXGI_FORMAT eDXGIFormat, uint32 uMipSlice, GLenum eTarget, CContext* pContext) { uint32 uNumElements(kDimDesc.ArraySize == -1 ? (pTexture->m_uNumElements - kDimDesc.FirstArraySlice) : kDimDesc.ArraySize); return GetView(pTexture, eDXGIFormat, eTarget, uMipSlice, kDimDesc.FirstArraySlice, uNumElements, pContext); } template static TViewPtr GetViewMipLayers(STexture* pTexture, const DimDesc& kDimDesc, DXGI_FORMAT eDXGIFormat, GLenum eTarget, CContext* pContext) { uint32 uNumElements(kDimDesc.ArraySize == -1 ? (pTexture->m_uNumElements - kDimDesc.FirstArraySlice) : kDimDesc.ArraySize); return GetViewMip(pTexture, kDimDesc, eDXGIFormat, eTarget, kDimDesc.FirstArraySlice, uNumElements, pContext); } template static TViewPtr GetView(SBuffer* pBuffer, const DimDesc& kDimDesc, DXGI_FORMAT eDXGIFormat, UINT uFlags, CContext* pContext) { return pBuffer->CreateUnorderedAccessView(GetGIFormat(eDXGIFormat), kDimDesc.FirstElement, kDimDesc.NumElements, uFlags, pContext); } template static TViewPtr GetViewEx(SBuffer* pBuffer, const DimDesc& kDimDesc, DXGI_FORMAT eDXGIFormat, CContext* pContext) { return GetView(pBuffer, kDimDesc, eDXGIFormat, kDimDesc, kDimDesc.Flags); } }; template struct SOutputMergerViewImpl : SResourceViewBaseImpl { static typename SOutputMergerViewImpl::TViewPtr GetView(STexture* pTexture, DXGI_FORMAT eDXGIFormat, GLenum, uint32 uMipLevel, uint32, uint32 uMinElement, uint32 uNumElements, CContext* pContext) { return pTexture->GetCompatibleOutputMergerView(SOutputMergerTextureViewConfiguration(GetGIFormat(eDXGIFormat), uMipLevel, uMinElement, uNumElements), pContext); } template static typename SOutputMergerViewImpl::TViewPtr GetViewMip(STexture* pTexture, const DimDesc& kDimDesc, DXGI_FORMAT eDXGIFormat, GLenum eTarget, uint32 uMinElement, uint32 uNumElements, CContext* pContext) { return GetView(pTexture, eDXGIFormat, eTarget, kDimDesc.MipSlice, 1, uMinElement, uNumElements, pContext); } template static typename SOutputMergerViewImpl::TViewPtr GetViewLayers(STexture* pTexture, const DimDesc& kDimDesc, DXGI_FORMAT eDXGIFormat, GLenum eTarget, uint32 uMinLevel, uint32 uNumLevels, CContext* pContext) { uint32 uNumElements(kDimDesc.ArraySize == -1 ? (pTexture->m_uNumElements - kDimDesc.FirstArraySlice) : kDimDesc.ArraySize); return GetView(pTexture, eDXGIFormat, eTarget, uMinLevel, uNumLevels, kDimDesc.FirstArraySlice, uNumElements, pContext); } template static typename SOutputMergerViewImpl::TViewPtr GetViewMipLayers(STexture* pTexture, const DimDesc& kDimDesc, DXGI_FORMAT eDXGIFormat, GLenum eTarget, CContext* pContext) { uint32 uNumElements(kDimDesc.ArraySize == -1 ? (pTexture->m_uNumElements - kDimDesc.FirstArraySlice) : kDimDesc.ArraySize); return GetViewMip(pTexture, kDimDesc, eDXGIFormat, eTarget, kDimDesc.FirstArraySlice, uNumElements, pContext); } }; struct SRenderTargetViewImpl : SOutputMergerViewImpl { enum EViewDimension { DIMENSION_BUFFER = D3D11_RTV_DIMENSION_BUFFER, DIMENSION_TEXTURE1D = D3D11_RTV_DIMENSION_TEXTURE1D, DIMENSION_TEXTURE1DARRAY = D3D11_RTV_DIMENSION_TEXTURE1DARRAY, DIMENSION_TEXTURE2D = D3D11_RTV_DIMENSION_TEXTURE2D, DIMENSION_TEXTURE2DARRAY = D3D11_RTV_DIMENSION_TEXTURE2DARRAY, DIMENSION_TEXTURE2DMS = D3D11_RTV_DIMENSION_TEXTURE2DMS, DIMENSION_TEXTURE2DMSARRAY = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY, DIMENSION_TEXTURE3D = D3D11_RTV_DIMENSION_TEXTURE3D }; }; struct SDepthStencilViewImpl : SOutputMergerViewImpl { enum EViewDimension { DIMENSION_TEXTURE1D = D3D11_DSV_DIMENSION_TEXTURE1D, DIMENSION_TEXTURE1DARRAY = D3D11_DSV_DIMENSION_TEXTURE1DARRAY, DIMENSION_TEXTURE2D = D3D11_DSV_DIMENSION_TEXTURE2D, DIMENSION_TEXTURE2DARRAY = D3D11_DSV_DIMENSION_TEXTURE2DARRAY, DIMENSION_TEXTURE2DMS = D3D11_DSV_DIMENSION_TEXTURE2DMS, DIMENSION_TEXTURE2DMSARRAY = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY, }; }; template typename Impl::TViewPtr GetTexture1DView(STexture* pTexture, const typename Impl::TViewDesc& kViewDesc, CContext* pContext) { switch (static_cast(kViewDesc.ViewDimension)) { case Impl::DIMENSION_TEXTURE1D: return Impl::GetViewMip(pTexture, kViewDesc.Texture1D, kViewDesc.Format, GL_TEXTURE_1D, 0, 1, pContext); case Impl::DIMENSION_TEXTURE1DARRAY: return Impl::GetViewMipLayers(pTexture, kViewDesc.Texture1DArray, kViewDesc.Format, GL_TEXTURE_1D_ARRAY, pContext); } return NULL; } template typename Impl::TViewPtr GetTexture2DView(STexture* pTexture, const typename Impl::TViewDesc& kViewDesc, CContext* pContext) { switch (static_cast(kViewDesc.ViewDimension)) { case Impl::DIMENSION_TEXTURE2D: return Impl::GetViewMip(pTexture, kViewDesc.Texture2D, kViewDesc.Format, GL_TEXTURE_2D, 0, 1, pContext); case Impl::DIMENSION_TEXTURE2DARRAY: return Impl::GetViewMipLayers(pTexture, kViewDesc.Texture2DArray, kViewDesc.Format, GL_TEXTURE_2D_ARRAY, pContext); } return NULL; } template typename Impl::TViewPtr GetTexture2DMSView(STexture* pTexture, const typename Impl::TViewDesc& kViewDesc, CContext* pContext) { if (pContext->GetDevice()->IsFeatureSupported(eF_MultiSampledTextures)) { switch (static_cast(kViewDesc.ViewDimension)) { #if DXGL_SUPPORT_MULTISAMPLED_TEXTURES case Impl::DIMENSION_TEXTURE2DMS: return Impl::GetView(pTexture, kViewDesc.Format, GL_TEXTURE_2D_MULTISAMPLE, 0, 1, 0, 1, pContext); #if !DXGLES case Impl::DIMENSION_TEXTURE2DMSARRAY: return Impl::GetViewLayers(pTexture, kViewDesc.Texture2DMSArray, kViewDesc.Format, GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 0, 1, pContext); #endif //!DXGLES #endif //DXGL_SUPPORT_MULTISAMPLED_TEXTURES } } return NULL; } template typename Impl::TViewPtr GetTextureCubeView(STexture* pTexture, const typename Impl::TViewDesc& kViewDesc, CContext* pContext) { switch (static_cast(kViewDesc.ViewDimension)) { case D3D11_SRV_DIMENSION_TEXTURECUBE: return Impl::GetViewMip(pTexture, kViewDesc.TextureCube, kViewDesc.Format, GL_TEXTURE_CUBE_MAP, 0, 6, pContext); #if DXGL_SUPPORT_CUBEMAP_ARRAYS case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY: return Impl::GetViewMip(pTexture, kViewDesc.TextureCubeArray, kViewDesc.Format, GL_TEXTURE_CUBE_MAP_ARRAY, kViewDesc.TextureCubeArray.First2DArrayFace, 6 * kViewDesc.TextureCubeArray.NumCubes - kViewDesc.TextureCubeArray.First2DArrayFace, pContext); #endif //DXGL_SUPPORT_CUBEMAP_ARRAYS } return NULL; } template typename Impl::TViewPtr GetTexture3DView(STexture* pTexture, const typename Impl::TViewDesc& kViewDesc, CContext* pContext) { if ((uint32)kViewDesc.ViewDimension == (uint32)Impl::DIMENSION_TEXTURE3D) { return Impl::GetViewMip(pTexture, kViewDesc.Texture3D, kViewDesc.Format, GL_TEXTURE_3D, 0, 1, pContext); } return NULL; } template typename Impl::TViewPtr GetBufferView(SBuffer* pBuffer, const typename Impl::TViewDesc& kViewDesc, CContext* pContext) { if ((uint32)kViewDesc.ViewDimension == (uint32)Impl::DIMENSION_BUFFER) { return Impl::GetView(pBuffer, kViewDesc.Buffer, kViewDesc.Format, 0, pContext); } return NULL; } template typename Impl::TViewPtr GetBufferViewEx(SBuffer* pBuffer, const typename Impl::TViewDesc& kViewDesc, CContext* pContext) { if ((uint32)kViewDesc.ViewDimension == (uint32)Impl::DIMENSION_BUFFEREX) { return Impl::GetViewEx(pBuffer, kViewDesc.BufferEx, kViewDesc.Format, pContext); } return NULL; } SShaderViewPtr CreateShaderResourceView(SResource* pResource, D3D11_RESOURCE_DIMENSION eDimension, const D3D11_SHADER_RESOURCE_VIEW_DESC& kViewDesc, CContext* pContext) { DXGL_SCOPED_PROFILE("CreateShaderResourceView") typedef SShaderResourceViewImpl TImpl; SShaderViewPtr spView; switch (eDimension) { case D3D11_RESOURCE_DIMENSION_TEXTURE1D: spView = GetTexture1DView(static_cast(pResource), kViewDesc, pContext); break; case D3D11_RESOURCE_DIMENSION_TEXTURE2D: spView = GetTexture2DView(static_cast(pResource), kViewDesc, pContext); if (spView == NULL) { spView = GetTexture2DMSView(static_cast(pResource), kViewDesc, pContext); } if (spView == NULL) { spView = GetTextureCubeView(static_cast(pResource), kViewDesc, pContext); } break; case D3D11_RESOURCE_DIMENSION_TEXTURE3D: spView = GetTexture3DView(static_cast(pResource), kViewDesc, pContext); break; case D3D11_RESOURCE_DIMENSION_BUFFER: spView = GetBufferView(static_cast(pResource), kViewDesc, pContext); if (spView == NULL) { spView = GetBufferViewEx(static_cast(pResource), kViewDesc, pContext); } break; default: DXGL_ERROR("Invalid resource dimension for shader resource"); return NULL; } if (spView == NULL) { DXGL_ERROR("Invalid shader resource view parameters"); } return spView; } SShaderViewPtr CreateUnorderedAccessView(SResource* pResource, D3D11_RESOURCE_DIMENSION eDimension, const D3D11_UNORDERED_ACCESS_VIEW_DESC& kViewDesc, CContext* pContext) { DXGL_SCOPED_PROFILE("CreateShaderResourceView") typedef SUnorderedAccessViewImpl TImpl; SShaderViewPtr spView; switch (eDimension) { case D3D11_RESOURCE_DIMENSION_TEXTURE1D: spView = GetTexture1DView(static_cast(pResource), kViewDesc, pContext); break; case D3D11_RESOURCE_DIMENSION_TEXTURE2D: spView = GetTexture2DView(static_cast(pResource), kViewDesc, pContext); break; case D3D11_RESOURCE_DIMENSION_TEXTURE3D: spView = GetTexture3DView(static_cast(pResource), kViewDesc, pContext); break; case D3D11_RESOURCE_DIMENSION_BUFFER: spView = GetBufferView(static_cast(pResource), kViewDesc, pContext); break; default: DXGL_ERROR("Invalid resource dimension for shader resource"); return NULL; } if (spView == NULL) { DXGL_ERROR("Invalid shader resource view parameters"); } return spView; } SOutputMergerViewPtr CreateRenderTargetView(SResource* pResource, D3D11_RESOURCE_DIMENSION eDimension, const D3D11_RENDER_TARGET_VIEW_DESC& kViewDesc, CContext* pContext) { DXGL_SCOPED_PROFILE("CreateRenderTargetView") typedef SRenderTargetViewImpl TImpl; SOutputMergerViewPtr spView; switch (eDimension) { case D3D11_RESOURCE_DIMENSION_TEXTURE1D: spView = GetTexture1DView(static_cast(pResource), kViewDesc, pContext); break; case D3D11_RESOURCE_DIMENSION_TEXTURE2D: spView = GetTexture2DView(static_cast(pResource), kViewDesc, pContext); if (spView == NULL) { spView = GetTexture2DMSView(static_cast(pResource), kViewDesc, pContext); } break; case D3D11_RESOURCE_DIMENSION_TEXTURE3D: spView = GetTexture3DView(static_cast(pResource), kViewDesc, pContext); break; default: DXGL_ERROR("Invalid resource dimension for render target"); return NULL; } if (spView == NULL) { DXGL_ERROR("Invalid resource dimension for render target"); } return spView; } SOutputMergerViewPtr CreateDepthStencilView(SResource* pResource, D3D11_RESOURCE_DIMENSION eDimension, const D3D11_DEPTH_STENCIL_VIEW_DESC& kViewDesc, CContext* pContext) { DXGL_SCOPED_PROFILE("CreateDepthStencilView") typedef SDepthStencilViewImpl TImpl; SOutputMergerViewPtr spView; switch (eDimension) { case D3D11_RESOURCE_DIMENSION_TEXTURE1D: spView = GetTexture1DView(static_cast(pResource), kViewDesc, pContext); break; case D3D11_RESOURCE_DIMENSION_TEXTURE2D: spView = GetTexture2DView(static_cast(pResource), kViewDesc, pContext); if (spView == NULL) { spView = GetTexture2DMSView(static_cast(pResource), kViewDesc, pContext); } break; default: DXGL_ERROR("Invalid resource dimension for depth stencil"); return NULL; } if (spView == NULL) { DXGL_ERROR("Invalid resource dimension for depth stencil"); } return spView; } }