Прямая запись в текстуру D3D из ядра
Я играю с декодером NVDEC H.264 из образцов NVIDIA CUDA, одна вещь, которую я обнаружил, - это когда кадр декодируется, он конвертируется из NV12 в буфер BGRA, который выделяется на стороне CUDA, затем этот буфер копируется в D3D BGRA текстура.
Я считаю, что это не очень эффективно с точки зрения использования памяти, и хочу преобразовать кадр NV12 напрямую в текстуру D3D с помощью этого ядра:
void Nv12ToBgra32(uint8_t *dpNv12, int nNv12Pitch, uint8_t *dpBgra, int nBgraPitch, int nWidth, int nHeight, int iMatrix)
Итак, создайте текстуру D3D (BGRA, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS, D3D11_CPU_ACCESS_WRITE, 1 mipmap), затем зарегистрируйте и запишите ее на стороне CUDA:
//Register
ck(cuGraphicsD3D11RegisterResource(&cuTexResource, textureResource, CU_GRAPHICS_REGISTER_FLAGS_NONE));
...
//Write output:
CUarray retArray;
ck(cuGraphicsMapResources(1, &cuTexResource, 0));
ck(cuGraphicsSubResourceGetMappedArray(&retArray, cuTexResource, 0, 0));
/*
yuvFramePtr (NV12) is uint8_t* from decoded frame,
it's stored within CUDA memory I believe
*/
Nv12ToBgra32(yuvFramePtr, w, (uint8_t*)retArray, 4 * w, w, h);
ck(cuGraphicsUnmapResources(1, &cuTexResource, 0));
Как только ядро вызывается, я получаю сбой. Может быть, из-за неправильного использования CUarray, может ли кто-нибудь пояснить, как использовать вывод cuGraphicsSubResourceGetMappedArray для записи памяти текстур из ядра CUDA? (поскольку требуется только запись необработанной памяти, нет необходимости обрабатывать правильное ограничение, фильтрацию и масштабирование значений)
1 ответ
Хорошо, для тех, кто борется с вопросом «Как написать текстуру D3D11 из ядра CUDA», вот как:
Создайте текстуру D3D с помощью D3D11_BIND_UNORDERED_ACCESS. Затем зарегистрируйте ресурс:
//ID3D11Texture2D *textureResource from D3D texture
CUgraphicsResource cuTexResource;
ck(cuGraphicsD3D11RegisterResource(&cuTexResource, textureResource, CU_GRAPHICS_REGISTER_FLAGS_NONE));
//You can also add write-discard if texture will be fully written by kernel
ck(cuGraphicsResourceSetMapFlags(cuTexResource, CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD));
Как только текстура создана и зарегистрирована, мы можем использовать ее как поверхность для записи.
ck(cuGraphicsMapResources(1, &cuTexResource, 0));
//Get array for first mip-map
CUArray retArray;
ck(cuGraphicsSubResourceGetMappedArray(&retArray, cuTexResource, 0, 0));
//Create surface from texture
CUsurfObject surf;
CUDA_RESOURCE_DESC surfDesc{};
surfDesc.res.array.hArray = retArray;
surfDesc.resType = CU_RESOURCE_TYPE_ARRAY;
ck(cuSurfObjectCreate(&surf, &surfDesc));
/*
Kernel declaration is:
void Nv12ToBgra32Surf(uint8_t* dpNv12, int nNv12Pitch, cudaSurfaceObject_t surf, int nBgraPitch, int nWidth, int nHeight, int iMatrix)
Surface write:
surf2Dwrite<uint>(VALUE, surf, x * sizeof(uint), y);
For BGRA surface we are writing uint, X offset is in bytes,
so multiply it with byte-size of type.
Run kernel:
*/
Nv12ToBgra32Surf(yuvFramePtr, w, /*out*/surf, 4 * w, w, h);
ck(cuGraphicsUnmapResources(1, &cuTexResource, 0));
ck(cuSurfObjectDestroy(surf));