Files
TheRock/rocm-systems/projects/clr/opencl/tests/ocltst/module/dx/OCLDX11YUY2.cpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

433 lines
13 KiB
C++

/*
* Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
*
* SPDX-License-Identifier: MIT
*/
#include "OCLDX11YUY2.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#define DXGI_FORMAT_NV12 103
#define DXGI_FORMAT_P010 104
#define GROUP_SIZE 256
const static char strKernel[] =
"__constant sampler_t imageSampler = CLK_NORMALIZED_COORDS_FALSE | "
"CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST; \n"
"__kernel void image2imageCopy( "
" \n"
" __read_only image2d_t input, "
" \n"
" __write_only image2d_t output) "
" \n"
"{ "
" \n"
" int2 coord = (int2)(get_global_id(0), get_global_id(1)); "
" \n"
" uint4 temp = read_imageui(input, imageSampler, coord); "
" \n"
" write_imageui(output, coord, temp); "
" \n"
"} "
" \n";
OCLDX11YUY2::OCLDX11YUY2() : OCLDX11Common() {
_numSubTests = 4;
blockSizeX = GROUP_SIZE;
blockSizeY = 1;
}
OCLDX11YUY2::~OCLDX11YUY2() {}
void OCLDX11YUY2::open(unsigned int test, char* units, double& conversion, unsigned int deviceId) {
dxDX11Texture = 0;
clImage2DOut = 0;
_openTest = test;
// Initialize random number seed
srand((unsigned int)time(NULL));
OCLDX11Common::open(test, units, conversion, deviceId);
if (_errorFlag) return;
if (!extensionsAvailable) {
return;
}
if (_openTest < 2) {
dxFormat = (DXGI_FORMAT)DXGI_FORMAT_NV12;
extensionsAvailable = formatSupported();
if (!extensionsAvailable) {
printf("DXGI_FORMAT_NV12 is required for this test!\n");
return;
}
} else {
dxFormat = (DXGI_FORMAT)DXGI_FORMAT_P010;
extensionsAvailable = formatSupported();
if (!extensionsAvailable) {
printf("DXGI_FORMAT_P010 is required for this test!\n");
return;
}
}
CompileKernel();
AllocateOpenCLImage();
}
void OCLDX11YUY2::run(void) {
if (_errorFlag) return;
if (!extensionsAvailable) return;
D3D11_TEXTURE2D_DESC Desc = {0};
Desc.ArraySize = 1;
Desc.BindFlags = 0;
Desc.Format = dxFormat;
Desc.Width = OCLDX11YUY2::WIDTH;
Desc.Height = OCLDX11YUY2::HEIGHT;
Desc.MipLevels = 1;
Desc.SampleDesc.Count = 1;
// Desc.MiscFlags=D3D11_RESOURCE_MISC_SHARED; //MM for fast GPU interop
// MM: these flags are incompatible with D3D11_RESOURCE_MISC_SHARED
// now we allocate texture without CPU access and if needed use temp texture
// (see FromSystemToDX11 and FromDX11ToSystem)
Desc.Usage = D3D11_USAGE_STAGING;
Desc.BindFlags = 0;
Desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
ID3D11Texture2D* pTextureTmp;
HRESULT hr = dxD3D11Device->CreateTexture2D(&Desc, NULL, &pTextureTmp);
// fill memory
D3D11_MAPPED_SUBRESOURCE LockedRectD11;
if (SUCCEEDED(hr)) {
hr = dxD3D11Context->Map(pTextureTmp, 0, D3D11_MAP_WRITE, 0, &LockedRectD11);
}
if (SUCCEEDED(hr)) {
// fill memory with something
for (int y = 0; y < OCLDX11YUY2::HEIGHT; y++) {
BYTE* pLine = (BYTE*)LockedRectD11.pData + y * LockedRectD11.RowPitch;
BYTE* pLineUV = (BYTE*)LockedRectD11.pData + y * LockedRectD11.RowPitch +
OCLDX11YUY2::HEIGHT * LockedRectD11.RowPitch;
for (int x = 0; x < OCLDX11YUY2::WIDTH; x++) {
*pLine++ = 0x7F; // Y
if (y < OCLDX11YUY2::HEIGHT / 2 && x < OCLDX11YUY2::WIDTH / 2) {
*pLineUV++ = 0x1F; // U
*pLineUV++ = 0x2F; // V
}
}
}
dxD3D11Context->Unmap(pTextureTmp, 0);
}
Desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
Desc.Usage = D3D11_USAGE_DEFAULT;
Desc.CPUAccessFlags = 0;
Desc.MiscFlags = (_openTest == 0) ? 0 : D3D11_RESOURCE_MISC_SHARED; // MM for fast GPU interop
hr = dxD3D11Device->CreateTexture2D(&Desc, NULL, &dxDX11Texture);
if (pTextureTmp != NULL) {
dxD3D11Context->CopySubresourceRegion(dxDX11Texture, 0, 0, 0, 0, pTextureTmp, 0, NULL);
pTextureTmp->Release();
}
testInterop();
}
void OCLDX11YUY2::AllocateOpenCLImage() {
cl_int status = 0;
cl_image_format format{};
format.image_channel_order = CL_R;
format.image_channel_data_type =
(dxFormat == DXGI_FORMAT_NV12) ? CL_UNSIGNED_INT8 : CL_UNSIGNED_INT16;
cl_image_desc descr{};
descr.image_type = CL_MEM_OBJECT_IMAGE2D;
descr.image_width = WIDTH;
descr.image_height = HEIGHT + HEIGHT / 2;
clImage2DOut = clCreateImage(context_, CL_MEM_WRITE_ONLY, &format, &descr, NULL, &status);
CHECK_RESULT((status != CL_SUCCESS), "AllocateOpenCLImage() failed");
}
void OCLDX11YUY2::testInterop() {
// alloc
cl_int clStatus = 0;
cl_mem clImage2D = clCreateFromD3D11Texture2DKHR(context_, 0, dxDX11Texture, 0, &clStatus);
CHECK_RESULT((clStatus != CL_SUCCESS), "clCreateFromD3D11Texture2DKHR() failed");
// bring objects to the queue
cl_event clEvent = NULL;
clEnqueueAcquireD3D11ObjectsKHR(_queue, 1, &clImage2D, 0, NULL, &clEvent);
clStatus = clWaitForEvents(1, &clEvent);
clReleaseEvent(clEvent);
CopyOpenCLImage(clImage2D);
bool ImageReadWorks = CheckCLImage(clImage2D);
bool bKernelWorks = CheckCLImage(clImage2DOut);
CHECK_RESULT_NO_RETURN((ImageReadWorks != true), "CheckCLImage(clImage2D) failed");
CHECK_RESULT_NO_RETURN((bKernelWorks != true), "CheckCLImage(clImage2DOut) failed");
cl_mem planeY = clGetPlaneFromImageAMD(context_, clImage2D, 0, &clStatus);
CHECK_RESULT((clStatus != CL_SUCCESS),
"clGetPlaneFromImageAMD(context_,clImage2D,0,&clStatus) failed");
cl_mem planeUV = clGetPlaneFromImageAMD(context_, clImage2D, 1, &clStatus);
CHECK_RESULT((clStatus != CL_SUCCESS),
"clGetPlaneFromImageAMD(context_,clImage2D,1,&clStatus) failed");
bool ImageWorksY = CheckCLImageY(planeY);
bool ImageWorksUV = CheckCLImageUV(planeUV);
clReleaseMemObject(planeY);
clReleaseMemObject(planeUV);
// release
clEvent = NULL;
// release object from the queue
clStatus = clEnqueueReleaseD3D11ObjectsKHR(_queue, 1, &clImage2D, 0, NULL, &clEvent);
clStatus = clWaitForEvents(1, &clEvent);
clReleaseEvent(clEvent);
// release mem object
clReleaseMemObject(clImage2D);
CHECK_RESULT_NO_RETURN((ImageWorksY != true), "CheckCLImageY() failed");
CHECK_RESULT_NO_RETURN((ImageWorksUV != true), "CheckCLImageUV() failed");
}
unsigned int OCLDX11YUY2::close(void) {
if (clImage2DOut) clReleaseMemObject(clImage2DOut);
if (dxDX11Texture) dxDX11Texture->Release();
return OCLDX11Common::close();
}
bool OCLDX11YUY2::CheckCLImage(cl_mem clImage) {
cl_int clStatus = 0;
size_t pitch = 0;
clStatus = clGetImageInfo(clImage, CL_IMAGE_ROW_PITCH, sizeof(pitch), &pitch, NULL);
pitch *= 2;
cl_image_format format;
clStatus = clGetImageInfo(clImage, CL_IMAGE_FORMAT, sizeof(format), &format, NULL);
size_t height;
clStatus = clGetImageInfo(clImage, CL_IMAGE_HEIGHT, sizeof(height), &height, NULL);
CHECK_RESULT_NO_RETURN(height != (HEIGHT + HEIGHT / 2),
"CheckCLImage: height!=(HEIGHT+HEIGHT/2)");
char* pTempBuffer = new char[(HEIGHT + HEIGHT / 2) * pitch];
size_t origin[] = {0, 0, 0};
size_t region[] = {WIDTH, HEIGHT + HEIGHT / 2, 1};
clStatus = clEnqueueReadImage(_queue, clImage, 1, origin, region, pitch, 0, pTempBuffer, 0, 0, 0);
::clFinish(_queue);
// test
bool bBreak = false;
for (int y = 0; y < HEIGHT && !bBreak; y++) {
char* pLine = (char*)pTempBuffer + y * pitch;
char* pLineUV = (char*)pTempBuffer + y * pitch + HEIGHT * pitch;
for (int x = 0; x < WIDTH; x++) {
if (*pLine != 0x7F) // Y
{
bBreak = true;
break;
}
pLine++;
if (y < HEIGHT / 2 && x < WIDTH / 2) {
if (*pLineUV != 0x1F) // U
{
bBreak = true;
break;
}
pLineUV++;
if (*pLineUV != 0x2F) // V
{
bBreak = true;
break;
}
pLineUV++;
}
}
}
delete[] pTempBuffer;
return !bBreak;
}
bool OCLDX11YUY2::CheckCLImageY(cl_mem clImage) {
cl_int clStatus = 0;
size_t pitch = 0;
clStatus = clGetImageInfo(clImage, CL_IMAGE_ROW_PITCH, sizeof(pitch), &pitch, NULL);
pitch *= 2;
cl_image_format format;
clStatus = clGetImageInfo(clImage, CL_IMAGE_FORMAT, sizeof(format), &format, NULL);
size_t height;
clStatus = clGetImageInfo(clImage, CL_IMAGE_HEIGHT, sizeof(height), &height, NULL);
CHECK_RESULT_NO_RETURN(height != HEIGHT, "CheckCLImageY: height!=HEIGHT");
char* pTempBuffer = new char[HEIGHT * pitch];
size_t origin[] = {0, 0, 0};
size_t region[] = {WIDTH, HEIGHT, 1};
clStatus = clEnqueueReadImage(_queue, clImage, 1, origin, region, pitch, 0, pTempBuffer, 0, 0, 0);
::clFinish(_queue);
// test
bool bBreak = false;
for (int y = 0; y < HEIGHT && !bBreak; y++) {
char* pLine = (char*)pTempBuffer + y * pitch;
for (int x = 0; x < WIDTH; x++) {
if (*pLine != 0x7F) // Y
{
bBreak = true;
break;
}
pLine++;
}
}
delete[] pTempBuffer;
return !bBreak;
}
bool OCLDX11YUY2::CheckCLImageUV(cl_mem clImage) {
cl_int clStatus = 0;
size_t pitch = 0;
clStatus = clGetImageInfo(clImage, CL_IMAGE_ROW_PITCH, sizeof(pitch), &pitch, NULL);
pitch *= 2;
size_t width = 0;
clStatus = clGetImageInfo(clImage, CL_IMAGE_WIDTH, sizeof(width), &width, NULL);
cl_image_format format;
clStatus = clGetImageInfo(clImage, CL_IMAGE_FORMAT, sizeof(format), &format, NULL);
size_t height;
clStatus = clGetImageInfo(clImage, CL_IMAGE_HEIGHT, sizeof(height), &height, NULL);
CHECK_RESULT_NO_RETURN(height != HEIGHT / 2, "CheckCLImageUV: height!=HEIGHT/2");
char* pTempBuffer = new char[(HEIGHT / 2) * pitch];
size_t origin[] = {0, 0, 0};
size_t region[] = {WIDTH / 2, HEIGHT / 2, 1};
clStatus = clEnqueueReadImage(_queue, clImage, 1, origin, region, pitch, 0, pTempBuffer, 0, 0, 0);
::clFinish(_queue);
bool bBreak = false;
for (int y = 0; y < HEIGHT / 2 && !bBreak; y++) {
char* pLineUV = (char*)pTempBuffer + y * pitch;
for (int x = 0; x < WIDTH / 2; x++) {
if (*pLineUV != 0x1F) // U
{
bBreak = true;
break;
}
pLineUV++;
if (*pLineUV != 0x2F) // V
{
bBreak = true;
break;
}
pLineUV++;
}
}
delete[] pTempBuffer;
return !bBreak;
}
void OCLDX11YUY2::CopyOpenCLImage(cl_mem clImageSrc) {
cl_int status = 0;
// Set appropriate arguments to the kernel2D
// input buffer image
status = clSetKernelArg(kernel_, 0, sizeof(cl_mem), &clImageSrc);
CHECK_RESULT((status != CL_SUCCESS),
"CopyOpenCLImage() failed at "
"clSetKernelArg(kernel_,0,sizeof(cl_mem),&clImageSrc)");
status = clSetKernelArg(kernel_, 1, sizeof(cl_mem), &clImage2DOut);
CHECK_RESULT((status != CL_SUCCESS),
"CopyOpenCLImage() failed at "
"clSetKernelArg(kernel_,1,sizeof(cl_mem),&clImage2DOut)");
// Enqueue a kernel run call.
size_t global_work_offset[] = {0, 0};
size_t globalThreads[] = {WIDTH, HEIGHT + HEIGHT / 2};
size_t localThreads[] = {blockSizeX, blockSizeY};
// status =
// clEnqueueNDRangeKernel(_queue,kernel_,2,NULL,globalThreads,localThreads,0,NULL,0);
status = clEnqueueNDRangeKernel(_queue, kernel_, 2, NULL, globalThreads, NULL, 0, NULL, 0);
CHECK_RESULT((status != CL_SUCCESS), "CopyOpenCLImage() failed at clEnqueueNDRangeKernel");
status = clFinish(_queue);
CHECK_RESULT((status != CL_SUCCESS), "CopyOpenCLImage() failed at clFinish");
}
void OCLDX11YUY2::CompileKernel() {
cl_int status = 0;
size_t kernelSize = sizeof(strKernel);
const char* strs = (const char*)&strKernel[0];
program_ = _wrapper->clCreateProgramWithSource(context_, 1, &strs, &kernelSize, &status);
status = _wrapper->clBuildProgram(program_, 1, &devices_[_deviceId], NULL, NULL, NULL);
if (status != CL_SUCCESS) {
if (status == CL_BUILD_PROGRAM_FAILURE) {
cl_int logStatus;
size_t buildLogSize = 0;
logStatus = clGetProgramBuildInfo(program_, devices_[_deviceId], CL_PROGRAM_BUILD_LOG,
buildLogSize, NULL, &buildLogSize);
std::string buildLog;
buildLog.resize(buildLogSize);
logStatus = clGetProgramBuildInfo(program_, devices_[_deviceId], CL_PROGRAM_BUILD_LOG,
buildLogSize, &buildLog[0], NULL);
printf("%s", buildLog.c_str());
}
return;
}
// get a kernel object handle for a kernel with the given name
kernel_ = _wrapper->clCreateKernel(program_, "image2imageCopy", &status);
size_t kernel2DWorkGroupSize = 0;
status = clGetKernelWorkGroupInfo(kernel_, devices_[_deviceId], CL_KERNEL_WORK_GROUP_SIZE,
sizeof(size_t), &kernel2DWorkGroupSize, 0);
if ((blockSizeX * blockSizeY) > kernel2DWorkGroupSize) {
if (blockSizeX > kernel2DWorkGroupSize) {
blockSizeX = kernel2DWorkGroupSize;
blockSizeY = 1;
}
}
}
bool OCLDX11YUY2::formatSupported() {
UINT supported = 0u;
dxD3D11Device->CheckFormatSupport(dxFormat, (UINT*)&supported);
return supported & D3D11_FORMAT_SUPPORT_TEXTURE2D;
}