blob: abfdbf0640b4aee2c197b323e680b7ce79ceb6da [file] [log] [blame]
//
// Copyright (c) 2017 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#define _CRT_SECURE_NO_WARNINGS
#include "harness.h"
#include <vector>
Texture2DSize texture2DSizes[] =
{
{
4, // Width
4, // Height
1, // MipLevels
1, // ArraySize
1, // SubResourceCount
{ // SubResources
{0, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
},
0, // MiscFlags
},
{
15, // Width
37, // Height
2, // MipLevels
1, // ArraySize
2, // SubResourceCount
{ // SubResources
{0, 0}, // MipLevel, ArraySlice
{1, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
},
0, // MiscFlags
},
{
65, // Width
17, // Height
1, // MipLevels
1, // ArraySize
1, // SubResourceCount
{ // SubResources
{0, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
},
D3D11_RESOURCE_MISC_SHARED, // MiscFlags
},
{
127, // Width
125, // Height
4, // MipLevels
1, // ArraySize
4, // SubResourceCount
{ // SubResources
{3, 0}, // MipLevel, ArraySlice
{2, 0}, // MipLevel, ArraySlice
{1, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
},
0, // MiscFlags
},
{
128, // Width
128, // Height
4, // MipLevels
6, // ArraySize
4, // SubResourceCount
{ // SubResources
{0, 1}, // MipLevel, ArraySlice
{1, 0}, // MipLevel, ArraySlice
{0, 2}, // MipLevel, ArraySlice
{3, 5}, // MipLevel, ArraySlice
},
0, // MiscFlags
},
{
256, // Width
256, // Height
0, // MipLevels
256, // ArraySize
4, // SubResourceCount
{ // SubResources
{0, 0}, // MipLevel, ArraySlice
{1, 255}, // MipLevel, ArraySlice
{2, 127}, // MipLevel, ArraySlice
{3, 128}, // MipLevel, ArraySlice
},
0, // MiscFlags
},
{
258, // Width
511, // Height
1, // MipLevels
1, // ArraySize
1, // SubResourceCount
{ // SubResources
{0, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
},
0, // MiscFlags
},
{
767, // Width
1025, // Height
4, // MipLevels
1, // ArraySize
1, // SubResourceCount
{ // SubResources
{0, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
},
0, // MiscFlags
},
{
2048, // Width
2048, // Height
1, // MipLevels
1, // ArraySize
1, // SubResourceCount
{ // SubResources
{0, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
{0, 0}, // MipLevel, ArraySlice
},
0, // MiscFlags
},
};
UINT texture2DSizeCount = sizeof(texture2DSizes)/sizeof(texture2DSizes[0]);
const char *
texture2DPatterns[2][2] =
{
{"aAbBcCdDeEfFgGhHiIjJ", "AaBbCcDdEeFfGgHhIiJj"},
{"zZyYxXwWvVuUtTsSrRqQ", "ZzYyXxWwVvUuTtSsRrQq"},
};
void SubTestTexture2D(
cl_context context,
cl_command_queue command_queue,
cl_kernel kernel,
ID3D11Device* pDevice,
ID3D11DeviceContext* pDC,
const TextureFormat* format,
const Texture2DSize* size)
{
ID3D11Texture2D* pTexture = NULL;
HRESULT hr = S_OK;
cl_image_format clFormat;
cl_int result = CL_SUCCESS;
HarnessD3D11_TestBegin("2D Texture: Format=%s, Width=%d, Height=%d, MipLevels=%d, ArraySize=%d",
format->name_format,
size->Width,
size->Height,
size->MipLevels,
size->ArraySize);
struct
{
cl_mem mem;
UINT subResource;
UINT width;
UINT height;
}
subResourceInfo[4];
cl_event events[4] = {NULL, NULL, NULL, NULL};
// create the D3D11 resources
{
D3D11_TEXTURE2D_DESC desc;
memset(&desc, 0, sizeof(desc) );
desc.Width = size->Width;
desc.Height = size->Height;
desc.MipLevels = size->MipLevels;
desc.ArraySize = size->ArraySize;
desc.Format = format->format;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
desc.CPUAccessFlags = 0;
desc.MiscFlags = 0;
hr = pDevice->CreateTexture2D(&desc, NULL, &pTexture);
TestRequire(SUCCEEDED(hr), "ID3D11Device::CreateTexture2D failed (non-OpenCL D3D error, but test is invalid).");
}
// initialize some useful variables
for (UINT i = 0; i < size->SubResourceCount; ++i)
{
// compute the expected values for the subresource
subResourceInfo[i].subResource = D3D11CalcSubresource(
size->subResources[i].MipLevel,
size->subResources[i].ArraySlice,
size->MipLevels);
subResourceInfo[i].width = size->Width;
subResourceInfo[i].height = size->Height;
for (UINT j = 0; j < size->subResources[i].MipLevel; ++j) {
subResourceInfo[i].width /= 2;
subResourceInfo[i].height /= 2;
}
subResourceInfo[i].mem = NULL;
}
// copy a pattern into the corners of the image, coordinates
// (0,0), (w,0-1), (0,h-1), (w-1,h-1)
for (UINT i = 0; i < size->SubResourceCount; ++i)
for (UINT x = 0; x < 2; ++x)
for (UINT y = 0; y < 2; ++y)
{
// create the staging buffer
ID3D11Texture2D* pStagingBuffer = NULL;
{
D3D11_TEXTURE2D_DESC desc = {0};
desc.Width = 1;
desc.Height = 1;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = format->format;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
hr = pDevice->CreateTexture2D(&desc, NULL, &pStagingBuffer);
TestRequire(SUCCEEDED(hr), "ID3D11Device::CreateTexture2D failed (non-OpenCL D3D error, but test is invalid).");
}
// write the data to the staging buffer
{
D3D11_MAPPED_SUBRESOURCE mappedTexture;
hr = pDC->Map(
pStagingBuffer,
0,
D3D11_MAP_READ_WRITE,
0,
&mappedTexture);
memcpy(mappedTexture.pData, texture2DPatterns[x][y], format->bytesPerPixel);
pDC->Unmap(pStagingBuffer, 0);
}
// copy the data to to the texture
{
D3D11_BOX box = {0};
box.front = 0; box.back = 1;
box.top = 0; box.bottom = 1;
box.left = 0; box.right = 1;
pDC->CopySubresourceRegion(
pTexture,
subResourceInfo[i].subResource,
x ? subResourceInfo[i].width - 1 : 0,
y ? subResourceInfo[i].height - 1 : 0,
0,
pStagingBuffer,
0,
&box);
}
pStagingBuffer->Release();
}
// create the cl_mem objects for the resources and verify its sanity
for (UINT i = 0; i < size->SubResourceCount; ++i)
{
// create a cl_mem for the resource
subResourceInfo[i].mem = clCreateFromD3D11Texture2DKHR(
context,
0,
pTexture,
subResourceInfo[i].subResource,
&result);
if (CL_IMAGE_FORMAT_NOT_SUPPORTED == result)
{
goto Cleanup;
}
TestRequire(result == CL_SUCCESS, "clCreateFromD3D11Texture2DKHR failed");
// query resource pointer and verify
ID3D11Resource* clResource = NULL;
result = clGetMemObjectInfo(
subResourceInfo[i].mem,
CL_MEM_D3D11_RESOURCE_KHR,
sizeof(clResource),
&clResource,
NULL);
TestRequire(result == CL_SUCCESS, "clGetMemObjectInfo for CL_MEM_D3D11_RESOURCE_KHR failed.");
TestRequire(clResource == pTexture, "clGetMemObjectInfo for CL_MEM_D3D11_RESOURCE_KHR returned incorrect value.");
// query subresource and verify
UINT clSubResource;
result = clGetImageInfo(
subResourceInfo[i].mem,
CL_IMAGE_D3D11_SUBRESOURCE_KHR,
sizeof(clSubResource),
&clSubResource,
NULL);
TestRequire(result == CL_SUCCESS, "clGetImageInfo for CL_IMAGE_D3D11_SUBRESOURCE_KHR failed");
TestRequire(clSubResource == subResourceInfo[i].subResource, "clGetImageInfo for CL_IMAGE_D3D11_SUBRESOURCE_KHR returned incorrect value.");
// query format and verify
result = clGetImageInfo(
subResourceInfo[i].mem,
CL_IMAGE_FORMAT,
sizeof(clFormat),
&clFormat,
NULL);
TestRequire(result == CL_SUCCESS, "clGetImageInfo for CL_IMAGE_FORMAT failed");
TestRequire(clFormat.image_channel_order == format->channel_order, "clGetImageInfo for CL_IMAGE_FORMAT returned incorrect channel order.");
TestRequire(clFormat.image_channel_data_type == format->channel_type, "clGetImageInfo for CL_IMAGE_FORMAT returned incorrect channel data type.");
// query width
size_t width;
result = clGetImageInfo(
subResourceInfo[i].mem,
CL_IMAGE_WIDTH,
sizeof(width),
&width,
NULL);
TestRequire(result == CL_SUCCESS, "clGetImageInfo for CL_IMAGE_WIDTH failed");
TestRequire(width == subResourceInfo[i].width, "clGetImageInfo for CL_IMAGE_HEIGHT returned incorrect value.");
// query height
size_t height;
result = clGetImageInfo(
subResourceInfo[i].mem,
CL_IMAGE_HEIGHT,
sizeof(height),
&height,
NULL);
TestRequire(result == CL_SUCCESS, "clGetImageInfo for CL_IMAGE_HEIGHT failed");
TestRequire(height == subResourceInfo[i].height, "clGetImageInfo for CL_IMAGE_HEIGHT returned incorrect value.");
}
// acquire the resources for OpenCL
for (UINT i = 0; i < 2; ++i)
{
cl_uint memCount = 0;
cl_mem memToAcquire[MAX_REGISTERED_SUBRESOURCES];
// cut the registered sub-resources into two sets and send the acquire calls for them separately
if (i == 0)
{
for(UINT j = 0; j < size->SubResourceCount/2; ++j)
{
memToAcquire[memCount++] = subResourceInfo[j].mem;
}
}
else
{
for(UINT j = size->SubResourceCount/2; j < size->SubResourceCount; ++j)
{
memToAcquire[memCount++] = subResourceInfo[j].mem;
}
}
if (!memCount) continue;
// do the acquire
result = clEnqueueAcquireD3D11ObjectsKHR(
command_queue,
memCount,
memToAcquire,
0,
NULL,
&events[0+i]);
TestRequire(result == CL_SUCCESS, "clEnqueueAcquireD3D11ObjectsKHR failed.");
TestRequire(events[0+i], "clEnqueueAcquireD3D11ObjectsKHR did not return an event.");
// make sure the event type is correct
cl_uint eventType = 0;
result = clGetEventInfo(
events[0+i],
CL_EVENT_COMMAND_TYPE,
sizeof(eventType),
&eventType,
NULL);
TestRequire(result == CL_SUCCESS, "clGetEventInfo for event created by clEnqueueAcquireD3D11ObjectsKHR failed.");
TestRequire(eventType == CL_COMMAND_ACQUIRE_D3D11_OBJECTS_KHR, "clGetEventInfo for CL_EVENT_COMMAND_TYPE was not CL_COMMAND_ACQUIRE_D3D11_OBJECTS_KHR.");
}
// download the data using OpenCL & compare with the expected results
for (UINT i = 0; i < size->SubResourceCount; ++i)
{
size_t origin[3] = {0,0,0};
size_t region[3] = {subResourceInfo[i].width, subResourceInfo[i].height, 1};
cl_mem tempImage;
cl_image_desc image_desc = { 0 };
image_desc.image_depth = 1;
image_desc.image_height = subResourceInfo[i].height;
image_desc.image_width = subResourceInfo[i].width;
image_desc.image_type = CL_MEM_OBJECT_IMAGE2D;
tempImage = clCreateImage(context, 0, &clFormat, &image_desc, NULL, &result);
TestRequire(result == CL_SUCCESS, "clCreateImage failed");
result = clEnqueueCopyImage(command_queue, subResourceInfo[i].mem, tempImage,
origin, origin, region, 0, NULL, NULL);
TestRequire(result == CL_SUCCESS, "clEnqueueCopyImage failed");
// copy (0,0) to (1,1) and (w-1,h-1) to (w-2,h-2) using a kernel
{
result = clSetKernelArg(
kernel,
0,
sizeof(cl_mem),
(void *)&tempImage);
result = clSetKernelArg(
kernel,
1,
sizeof(cl_mem),
(void *)&subResourceInfo[i].mem);
TestRequire(CL_SUCCESS == result, "clSetKernelArg failed");
size_t localWorkSize[] = {1};
size_t globalWorkSize[] = {1};
result = clEnqueueNDRangeKernel(
command_queue,
kernel,
1,
NULL,
globalWorkSize,
localWorkSize,
0,
NULL,
NULL);
TestRequire(CL_SUCCESS == result, "clEnqueueNDRangeKernel failed");
}
// copy (w-1,0) to (w-2,1) and (0,h) to (1,h-2) using a memcpy
for (UINT x = 0; x < 2; ++x)
for (UINT y = 0; y < 2; ++y)
{
if (x == y)
{
continue;
}
size_t src[3] =
{
x ? subResourceInfo[i].width - 1 : 0,
y ? subResourceInfo[i].height - 1 : 0,
0,
};
size_t dst[3] =
{
x ? subResourceInfo[i].width - 2 : 1,
y ? subResourceInfo[i].height - 2 : 1,
0,
};
size_t region[3] =
{
1,
1,
1,
};
result = clEnqueueCopyImage(
command_queue,
subResourceInfo[i].mem,
subResourceInfo[i].mem,
src,
dst,
region,
0,
NULL,
NULL);
TestRequire(result == CL_SUCCESS, "clEnqueueCopyImage failed.");
}
clReleaseMemObject(tempImage);
}
// release the resource from OpenCL
for (UINT i = 0; i < 2; ++i)
{
cl_uint memCount = 0;
cl_mem memToAcquire[MAX_REGISTERED_SUBRESOURCES];
// cut the registered sub-resources into two sets and send the release calls for them separately
if (i == 0)
{
for(UINT j = size->SubResourceCount/4; j < size->SubResourceCount; ++j)
{
memToAcquire[memCount++] = subResourceInfo[j].mem;
}
}
else
{
for(UINT j = 0; j < size->SubResourceCount/4; ++j)
{
memToAcquire[memCount++] = subResourceInfo[j].mem;
}
}
if (!memCount) continue;
// do the release
result = clEnqueueReleaseD3D11ObjectsKHR(
command_queue,
memCount,
memToAcquire,
0,
NULL,
&events[2+i]);
TestRequire(result == CL_SUCCESS, "clEnqueueReleaseD3D11ObjectsKHR failed.");
TestRequire(events[2+i], "clEnqueueReleaseD3D11ObjectsKHR did not return an event.");
// make sure the event type is correct
cl_uint eventType = 0;
result = clGetEventInfo(
events[2+i],
CL_EVENT_COMMAND_TYPE,
sizeof(eventType),
&eventType,
NULL);
TestRequire(result == CL_SUCCESS, "clGetEventInfo for event created by clEnqueueReleaseD3D11ObjectsKHR failed.");
TestRequire(eventType == CL_COMMAND_RELEASE_D3D11_OBJECTS_KHR, "clGetEventInfo for CL_EVENT_COMMAND_TYPE was not CL_COMMAND_RELEASE_D3D11_OBJECTS_KHR.");
}
for (UINT i = 0; i < size->SubResourceCount; ++i)
for (UINT x = 0; x < 2; ++x)
for (UINT y = 0; y < 2; ++y)
{
// create the staging buffer
ID3D11Texture2D* pStagingBuffer = NULL;
{
D3D11_TEXTURE2D_DESC desc = {0};
desc.Width = 1;
desc.Height = 1;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = format->format;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
hr = pDevice->CreateTexture2D(&desc, NULL, &pStagingBuffer);
TestRequire(SUCCEEDED(hr), "Failed to create staging buffer.");
}
// wipe out the staging buffer to make sure we don't get stale values
{
D3D11_MAPPED_SUBRESOURCE mappedTexture;
hr = pDC->Map(
pStagingBuffer,
0,
D3D11_MAP_READ_WRITE,
0,
&mappedTexture);
TestRequire(SUCCEEDED(hr), "Failed to map staging buffer");
memset(mappedTexture.pData, 0, format->bytesPerPixel);
pDC->Unmap(pStagingBuffer, 0);
}
// copy the pixel to the staging buffer
{
D3D11_BOX box = {0};
box.left = x ? subResourceInfo[i].width - 2 : 1; box.right = box.left + 1;
box.top = y ? subResourceInfo[i].height - 2 : 1; box.bottom = box.top + 1;
box.front = 0; box.back = 1;
pDC->CopySubresourceRegion(
pStagingBuffer,
0,
0,
0,
0,
pTexture,
subResourceInfo[i].subResource,
&box);
}
// make sure we read back what was written next door
{
D3D11_MAPPED_SUBRESOURCE mappedTexture;
hr = pDC->Map(
pStagingBuffer,
0,
D3D11_MAP_READ_WRITE,
0,
&mappedTexture);
TestRequire(SUCCEEDED(hr), "Failed to map staging buffer");
TestRequire(
!memcmp(mappedTexture.pData, texture2DPatterns[x][y], format->bytesPerPixel),
"Failed to map staging buffer");
pDC->Unmap(pStagingBuffer, 0);
}
pStagingBuffer->Release();
}
Cleanup:
if (pTexture)
{
pTexture->Release();
}
for (UINT i = 0; i < size->SubResourceCount; ++i)
{
clReleaseMemObject(subResourceInfo[i].mem);
}
for (UINT i = 0; i < 4; ++i)
{
if (events[i])
{
result = clReleaseEvent(events[i]);
TestRequire(result == CL_SUCCESS, "clReleaseEvent for event failed.");
}
}
HarnessD3D11_TestEnd();
}
bool is_format_supported(
cl_channel_order channel_order,
cl_channel_type channel_type,
const std::vector<cl_image_format> &supported_image_formats)
{
for (std::vector<cl_image_format>::const_iterator it = supported_image_formats.begin(); it != supported_image_formats.end(); ++it)
if (it->image_channel_data_type == channel_type && it->image_channel_order == channel_order)
return true;
return false;
}
void TestDeviceTexture2D(
cl_device_id device,
cl_context context,
cl_command_queue command_queue,
ID3D11Device* pDevice,
ID3D11DeviceContext* pDC)
{
cl_int result = CL_SUCCESS;
cl_kernel kernels[3] = {NULL, NULL, NULL};
const char *sourceRaw =
" \
__kernel void texture2D\n\
( \n\
__read_only image2d_t texIn, \n\
__write_only image2d_t texOut \n\
) \n\
{ \n\
const sampler_t smp = CLK_FILTER_NEAREST; \n\
CLK_NORMALIZED_COORDS_FALSE |\n\
CLK_ADDRESS_CLAMP_TO_EDGE; \n\
%s value; \n\
int2 coordIn; \n\
int2 coordOut; \n\
int w = get_image_width(texIn); \n\
int h = get_image_height(texIn); \n\
\n\
coordIn = (int2)(0, 0); \n\
coordOut = (int2)(1, 1); \n\
value = read_image%s(texIn, smp, coordIn); \n\
write_image%s(texOut, coordOut, value); \n\
\n\
coordIn = (int2)(w-1, h-1); \n\
coordOut = (int2)(w-2, h-2); \n\
value = read_image%s(texIn, smp, coordIn); \n\
write_image%s(texOut, coordOut, value); \n\
} \n\
";
cl_uint supported_formats_count;
std::vector<cl_image_format> supported_image_formats;
result = clGetSupportedImageFormats(context, CL_MEM_READ_ONLY, CL_MEM_OBJECT_IMAGE2D, 0, NULL, &supported_formats_count);
TestRequire(CL_SUCCESS == result, "clGetSupportedImageFormats failed.");
supported_image_formats.resize(supported_formats_count);
result = clGetSupportedImageFormats(context, CL_MEM_READ_ONLY, CL_MEM_OBJECT_IMAGE2D, supported_formats_count, &supported_image_formats[0], NULL);
TestRequire(CL_SUCCESS == result, "clGetSupportedImageFormats failed.");
char source[2048];
sprintf(source, sourceRaw, "float4", "f", "f", "f", "f");
result = HarnessD3D11_CreateKernelFromSource(&kernels[0], device, context, source, "texture2D");
TestRequire(CL_SUCCESS == result, "HarnessD3D11_CreateKernelFromSource failed.");
sprintf(source, sourceRaw, "uint4", "ui", "ui", "ui", "ui");
result = HarnessD3D11_CreateKernelFromSource(&kernels[1], device, context, source, "texture2D");
TestRequire(CL_SUCCESS == result, "HarnessD3D11_CreateKernelFromSource failed.");
sprintf(source, sourceRaw, "int4", "i", "i", "i", "i");
result = HarnessD3D11_CreateKernelFromSource(&kernels[2], device, context, source, "texture2D");
TestRequire(CL_SUCCESS == result, "HarnessD3D11_CreateKernelFromSource failed.");
for (UINT format = 0, size = 0; format < formatCount; ++size, ++format)
{
if (!is_format_supported(formats[format].channel_order, formats[format].channel_type, supported_image_formats))
{
HarnessD3D11_TestBegin("2D_texture: Format=%s, Width=%d, Height=%d, MipLevels=%d, ArraySize=%d\n",
formats[format].name_format,
texture2DSizes[size % texture2DSizeCount].Width,
texture2DSizes[size % texture2DSizeCount].Height,
texture2DSizes[size % texture2DSizeCount].MipLevels,
texture2DSizes[size % texture2DSizeCount].ArraySize);
log_info("\tFormat not supported, skipping test!\n");
HarnessD3D11_TestEnd();
continue;
}
SubTestTexture2D(
context,
command_queue,
kernels[formats[format].generic],
pDevice,
pDC,
&formats[format],
&texture2DSizes[size % texture2DSizeCount]);
}
Cleanup:
for (UINT i = 0; i < 3; ++i)
{
if (kernels[i])
{
clReleaseKernel(kernels[i]);
}
}
}