1
0
Fork 0
qsdecoder/d3d11_allocator.cpp

386 lines
12 KiB
C++

/*
* Copyright (c) 2013, INTEL CORPORATION
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* Neither the name of INTEL CORPORATION nor the names of its contributors may
* be used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "stdafx.h"
#if MFX_D3D11_SUPPORT
#include "QuickSync_defs.h"
#include "QuickSyncUtils.h"
#include "d3d11_allocator.h"
#define D3DFMT_NV12 (DXGI_FORMAT)MAKEFOURCC('N','V','1','2')
#define D3DFMT_YV12 (DXGI_FORMAT)MAKEFOURCC('Y','V','1','2')
//for generating sequence of mfx handles
template <typename T>
struct sequence {
T x;
sequence(T seed) : x(seed) { }
};
template <>
struct sequence<mfxHDL> {
mfxHDL x;
sequence(mfxHDL seed) : x(seed) { }
mfxHDL operator ()()
{
mfxHDL y = x;
x = (mfxHDL)(1 + (size_t)(x));
return y;
}
};
D3D11FrameAllocator::D3D11FrameAllocator()
{
m_pDeviceContext = NULL;
}
D3D11FrameAllocator::~D3D11FrameAllocator()
{
Close();
}
D3D11FrameAllocator::TextureSubResource D3D11FrameAllocator::GetResourceFromMid(mfxMemId mid)
{
size_t index = (size_t)MFXReadWriteMid(mid).raw() - 1;
if(m_memIdMap.size() <= index)
return TextureSubResource();
//reverse iterator dereferencing
TextureResource * p = &(*m_memIdMap[index]);
if (!p->bAlloc)
return TextureSubResource();
return TextureSubResource(p, mid);
}
mfxStatus D3D11FrameAllocator::Init(mfxAllocatorParams *pParams)
{
D3D11AllocatorParams *pd3d11Params = 0;
pd3d11Params = dynamic_cast<D3D11AllocatorParams *>(pParams);
if (NULL == pd3d11Params ||
NULL == pd3d11Params->pDevice)
{
return MFX_ERR_NOT_INITIALIZED;
}
m_initParams = *pd3d11Params;
MSDK_SAFE_RELEASE(m_pDeviceContext);
pd3d11Params->pDevice->GetImmediateContext(&m_pDeviceContext);
return MFX_ERR_NONE;
}
mfxStatus D3D11FrameAllocator::Close()
{
mfxStatus sts = BaseFrameAllocator::Close();
for(referenceType i = m_resourcesByRequest.begin(); i != m_resourcesByRequest.end(); i++)
{
i->Release();
}
m_resourcesByRequest.clear();
m_memIdMap.clear();
MSDK_SAFE_RELEASE(m_pDeviceContext);
return sts;
}
mfxStatus D3D11FrameAllocator::LockFrame(mfxMemId mid, mfxFrameData *ptr)
{
HRESULT hRes = S_OK;
D3D11_TEXTURE2D_DESC desc = {0};
D3D11_MAPPED_SUBRESOURCE lockedRect = {0};
//check that texture exists
TextureSubResource sr = GetResourceFromMid(mid);
if (!sr.GetTexture())
return MFX_ERR_LOCK_MEMORY;
D3D11_MAP mapType = D3D11_MAP_READ;
UINT mapFlags = D3D11_MAP_FLAG_DO_NOT_WAIT;
{
ASSERT(NULL != sr.GetStaging());
sr.GetTexture()->GetDesc(&desc);
if (DXGI_FORMAT_NV12 != desc.Format)
{
return MFX_ERR_LOCK_MEMORY;
}
#ifdef D3D11_PARALLEL_COPY
// copy original frame to staging frame - CPU can't access original frame
// parallel copy is a little faster
D3D11_BOX box;
MSDK_ZERO_VAR(box);
D3D11_TEXTURE2D_DESC desc;
sr.GetTexture()->GetDesc(&desc);
box.right = desc.Width;
box.bottom = desc.Height;
int count = 2;
ID3D11DeviceContext* pDeviceContext = m_pDeviceContext;
Concurrency::parallel_for(0, count+1, [pDeviceContext, &sr, &box, count](int i)
{
int block = MSDK_ALIGN16(box.bottom / count);
D3D11_BOX tmp_box = box;
tmp_box.top = i * block;
tmp_box.bottom = (i == count) ? box.bottom : tmp_box.top + block;
pDeviceContext->CopySubresourceRegion(sr.GetStaging(), 0, tmp_box.left, tmp_box.top, 0, sr.GetTexture(), sr.GetSubResource(), &tmp_box);
});
#else
// Single threaded copy
m_pDeviceContext->CopySubresourceRegion(sr.GetStaging(), 0, 0, 0, 0, sr.GetTexture(), sr.GetSubResource(), NULL);
#endif
do
{
hRes = m_pDeviceContext->Map(sr.GetStaging(), 0, mapType, mapFlags, &lockedRect);
if (S_OK != hRes && DXGI_ERROR_WAS_STILL_DRAWING != hRes)
{
MSDK_TRACE("ERROR: m_pDeviceContext->Map = 0x%lX\n", hRes);
}
}
while (DXGI_ERROR_WAS_STILL_DRAWING == hRes);
}
if (FAILED(hRes))
return MFX_ERR_LOCK_MEMORY;
MSDK_CHECK_NOT_EQUAL(desc.Format, DXGI_FORMAT_NV12, MFX_ERR_LOCK_MEMORY);
ptr->Pitch = (mfxU16)lockedRect.RowPitch;
ptr->Y = (mfxU8 *)lockedRect.pData;
ptr->U = (mfxU8 *)lockedRect.pData + desc.Height * lockedRect.RowPitch;
ptr->V = ptr->U + 1;
return MFX_ERR_NONE;
}
mfxStatus D3D11FrameAllocator::UnlockFrame(mfxMemId mid, mfxFrameData* ptr)
{
//check that texture exists
TextureSubResource sr = GetResourceFromMid(mid);
if (!sr.GetTexture())
return MFX_ERR_LOCK_MEMORY;
m_pDeviceContext->Unmap(sr.GetStaging(), 0);
if (ptr)
{
ptr->Pitch=0;
ptr->U = ptr->V = ptr->Y = NULL;
ptr->A = ptr->R = ptr->G = ptr->B = NULL;
}
return MFX_ERR_NONE;
}
mfxStatus D3D11FrameAllocator::GetFrameHDL(mfxMemId mid, mfxHDL *handle)
{
if (NULL == handle)
return MFX_ERR_INVALID_HANDLE;
TextureSubResource sr = GetResourceFromMid(mid);
if (!sr.GetTexture())
return MFX_ERR_INVALID_HANDLE;
mfxHDLPair *pPair = (mfxHDLPair*)handle;
pPair->first = sr.GetTexture();
pPair->second = (mfxHDL)(UINT_PTR)sr.GetSubResource();
return MFX_ERR_NONE;
}
mfxStatus D3D11FrameAllocator::CheckRequestType(mfxFrameAllocRequest *request)
{
mfxStatus sts = BaseFrameAllocator::CheckRequestType(request);
if (MSDK_FAILED(sts))
return sts;
if ((request->Type & (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET)) != 0)
return MFX_ERR_NONE;
else
return MFX_ERR_UNSUPPORTED;
}
mfxStatus D3D11FrameAllocator::ReleaseResponse(mfxFrameAllocResponse *response)
{
if (NULL == response)
return MFX_ERR_NULL_PTR;
if (response->mids && 0 != response->NumFrameActual)
{
//check whether texture exsist
TextureSubResource sr = GetResourceFromMid(response->mids[0]);
if (!sr.GetTexture())
return MFX_ERR_NULL_PTR;
sr.Release();
//if texture is last it is possible to remove also all handles from map to reduce fragmentation
//search for allocated chunk
if (m_resourcesByRequest.end() == std::find_if(m_resourcesByRequest.begin(), m_resourcesByRequest.end(), TextureResource::isAllocated))
{
m_resourcesByRequest.clear();
m_memIdMap.clear();
}
}
return MFX_ERR_NONE;
}
mfxStatus D3D11FrameAllocator::AllocImpl(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response)
{
HRESULT hRes;
DXGI_FORMAT colorFormat = ConverColortFormat(request->Info.FourCC);
// Only support NV12
MSDK_CHECK_NOT_EQUAL(colorFormat, DXGI_FORMAT_NV12, MFX_ERR_UNSUPPORTED);
TextureResource newTexture;
D3D11_TEXTURE2D_DESC desc = {0};
desc.Width = request->Info.Width;
desc.Height = request->Info.Height;
desc.MipLevels = 1;
//number of subresources is 1 in case of not single texture
desc.ArraySize = m_initParams.bUseSingleTexture ? request->NumFrameSuggested : 1;
desc.Format = ConverColortFormat(request->Info.FourCC);
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.MiscFlags = m_initParams.uncompressedResourceMiscFlags;
desc.BindFlags = D3D11_BIND_DECODER;
if ( (MFX_MEMTYPE_FROM_VPPIN & request->Type) && (DXGI_FORMAT_YUY2 == desc.Format) ||
(DXGI_FORMAT_B8G8R8A8_UNORM == desc.Format) )
{
desc.BindFlags = D3D11_BIND_RENDER_TARGET;
if (desc.ArraySize > 2)
return MFX_ERR_MEMORY_ALLOC;
}
if ( (MFX_MEMTYPE_FROM_VPPOUT & request->Type) ||
(MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET & request->Type))
{
desc.BindFlags = D3D11_BIND_RENDER_TARGET;
if (desc.ArraySize > 2)
return MFX_ERR_MEMORY_ALLOC;
}
if ( DXGI_FORMAT_P8 == desc.Format )
{
desc.BindFlags = 0;
}
ID3D11Texture2D* pTexture2D;
for (size_t i = 0; i < request->NumFrameSuggested / desc.ArraySize; ++i)
{
hRes = m_initParams.pDevice->CreateTexture2D(&desc, NULL, &pTexture2D);
if (FAILED(hRes))
{
MSDK_TRACE("CreateTexture2D(%d) failed, hr = 0x%lX\n", (int)i, hRes);
return MFX_ERR_MEMORY_ALLOC;
}
newTexture.textures.push_back(pTexture2D);
}
desc.ArraySize = 1;
desc.Usage = D3D11_USAGE_STAGING;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.BindFlags = 0;
desc.MiscFlags = 0;
for (size_t i = 0; i < request->NumFrameSuggested; ++i)
{
hRes = m_initParams.pDevice->CreateTexture2D(&desc, NULL, &pTexture2D);
if (FAILED(hRes))
{
MSDK_TRACE("Create staging texture(%d) failed hr = 0x%lX\n", (int)i, hRes);
return MFX_ERR_MEMORY_ALLOC;
}
newTexture.stagingTexture.push_back(pTexture2D);
}
// mapping to self created handles array, starting from zero or from last assigned handle + 1
sequence<mfxHDL> seq_initializer(m_resourcesByRequest.empty() ? 0 : m_resourcesByRequest.back().outerMids.back());
//incrementing starting index
//1. 0(NULL) is invalid memid
//2. back is last index not new one
seq_initializer();
std::generate_n(std::back_inserter(newTexture.outerMids), request->NumFrameSuggested, seq_initializer);
//saving texture resources
m_resourcesByRequest.push_back(newTexture);
//providing pointer to mids externally
response->mids = &m_resourcesByRequest.back().outerMids.front();
response->NumFrameActual = request->NumFrameSuggested;
//iterator prior end()
auto it_last = m_resourcesByRequest.end();
//fill map
std::fill_n(std::back_inserter(m_memIdMap), request->NumFrameSuggested, --it_last);
return MFX_ERR_NONE;
}
DXGI_FORMAT D3D11FrameAllocator::ConverColortFormat(mfxU32 fourcc)
{
switch (fourcc)
{
case MFX_FOURCC_NV12:
return DXGI_FORMAT_NV12;
case MFX_FOURCC_YUY2:
return DXGI_FORMAT_YUY2;
case MFX_FOURCC_RGB4:
return DXGI_FORMAT_B8G8R8A8_UNORM;
case MFX_FOURCC_P8:
case MFX_FOURCC_P8_TEXTURE:
return DXGI_FORMAT_P8;
default:
return DXGI_FORMAT_UNKNOWN;
}
}
#endif //#if MFX_D3D11_SUPPORT