blob: e6520b1c08b76aa1ebe082472ba045645d9113c7 [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.
//
#include "typeWrappers.h"
#include "kernelHelpers.h"
#include "errorHelpers.h"
#include <stdlib.h>
#include "clImageHelper.h"
#define ROUND_SIZE_UP(_size, _align) \
(((size_t)(_size) + (size_t)(_align)-1) & -((size_t)(_align)))
#if defined(__APPLE__)
#define kPageSize 4096
#include <sys/mman.h>
#include <stdlib.h>
#elif defined(__linux__)
#include <unistd.h>
#define kPageSize (getpagesize())
#endif
clProtectedImage::clProtectedImage(cl_context context, cl_mem_flags mem_flags,
const cl_image_format *fmt, size_t width,
cl_int *errcode_ret)
{
cl_int err = Create(context, mem_flags, fmt, width);
if (errcode_ret != NULL) *errcode_ret = err;
}
cl_int clProtectedImage::Create(cl_context context, cl_mem_flags mem_flags,
const cl_image_format *fmt, size_t width)
{
cl_int error;
#if defined(__APPLE__)
int protect_pages = 1;
cl_device_id devices[16];
size_t number_of_devices;
error = clGetContextInfo(context, CL_CONTEXT_DEVICES, sizeof(devices),
devices, &number_of_devices);
test_error(error, "clGetContextInfo for CL_CONTEXT_DEVICES failed");
number_of_devices /= sizeof(cl_device_id);
for (int i = 0; i < (int)number_of_devices; i++)
{
cl_device_type type;
error = clGetDeviceInfo(devices[i], CL_DEVICE_TYPE, sizeof(type), &type,
NULL);
test_error(error, "clGetDeviceInfo for CL_DEVICE_TYPE failed");
if (type == CL_DEVICE_TYPE_GPU)
{
protect_pages = 0;
break;
}
}
if (protect_pages)
{
size_t pixelBytes = get_pixel_bytes(fmt);
size_t rowBytes = ROUND_SIZE_UP(width * pixelBytes, kPageSize);
size_t rowStride = rowBytes + kPageSize;
// create backing store
backingStoreSize = rowStride + 8 * rowStride;
backingStore = mmap(0, backingStoreSize, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, 0, 0);
// add guard pages
size_t row;
char *p = (char *)backingStore;
char *imagePtr = (char *)backingStore + 4 * rowStride;
for (row = 0; row < 4; row++)
{
mprotect(p, rowStride, PROT_NONE);
p += rowStride;
}
p += rowBytes;
mprotect(p, kPageSize, PROT_NONE);
p += rowStride;
p -= rowBytes;
for (row = 0; row < 4; row++)
{
mprotect(p, rowStride, PROT_NONE);
p += rowStride;
}
if (getenv("CL_ALIGN_RIGHT"))
{
static int spewEnv = 1;
if (spewEnv)
{
log_info("***CL_ALIGN_RIGHT is set. Aligning images at right "
"edge of page\n");
spewEnv = 0;
}
imagePtr += rowBytes - pixelBytes * width;
}
image = create_image_1d(context, mem_flags | CL_MEM_USE_HOST_PTR, fmt,
width, rowStride, imagePtr, NULL, &error);
}
else
{
backingStore = NULL;
image = create_image_1d(context, mem_flags, fmt, width, 0, NULL, NULL,
&error);
}
#else
backingStore = NULL;
image =
create_image_1d(context, mem_flags, fmt, width, 0, NULL, NULL, &error);
#endif
return error;
}
clProtectedImage::clProtectedImage(cl_context context, cl_mem_flags mem_flags,
const cl_image_format *fmt, size_t width,
size_t height, cl_int *errcode_ret)
{
cl_int err = Create(context, mem_flags, fmt, width, height);
if (errcode_ret != NULL) *errcode_ret = err;
}
cl_int clProtectedImage::Create(cl_context context, cl_mem_flags mem_flags,
const cl_image_format *fmt, size_t width,
size_t height)
{
cl_int error;
#if defined(__APPLE__)
int protect_pages = 1;
cl_device_id devices[16];
size_t number_of_devices;
error = clGetContextInfo(context, CL_CONTEXT_DEVICES, sizeof(devices),
devices, &number_of_devices);
test_error(error, "clGetContextInfo for CL_CONTEXT_DEVICES failed");
number_of_devices /= sizeof(cl_device_id);
for (int i = 0; i < (int)number_of_devices; i++)
{
cl_device_type type;
error = clGetDeviceInfo(devices[i], CL_DEVICE_TYPE, sizeof(type), &type,
NULL);
test_error(error, "clGetDeviceInfo for CL_DEVICE_TYPE failed");
if (type == CL_DEVICE_TYPE_GPU)
{
protect_pages = 0;
break;
}
}
if (protect_pages)
{
size_t pixelBytes = get_pixel_bytes(fmt);
size_t rowBytes = ROUND_SIZE_UP(width * pixelBytes, kPageSize);
size_t rowStride = rowBytes + kPageSize;
// create backing store
backingStoreSize = height * rowStride + 8 * rowStride;
backingStore = mmap(0, backingStoreSize, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, 0, 0);
// add guard pages
size_t row;
char *p = (char *)backingStore;
char *imagePtr = (char *)backingStore + 4 * rowStride;
for (row = 0; row < 4; row++)
{
mprotect(p, rowStride, PROT_NONE);
p += rowStride;
}
p += rowBytes;
for (row = 0; row < height; row++)
{
mprotect(p, kPageSize, PROT_NONE);
p += rowStride;
}
p -= rowBytes;
for (row = 0; row < 4; row++)
{
mprotect(p, rowStride, PROT_NONE);
p += rowStride;
}
if (getenv("CL_ALIGN_RIGHT"))
{
static int spewEnv = 1;
if (spewEnv)
{
log_info("***CL_ALIGN_RIGHT is set. Aligning images at right "
"edge of page\n");
spewEnv = 0;
}
imagePtr += rowBytes - pixelBytes * width;
}
image = create_image_2d(context, mem_flags | CL_MEM_USE_HOST_PTR, fmt,
width, height, rowStride, imagePtr, &error);
}
else
{
backingStore = NULL;
image = create_image_2d(context, mem_flags, fmt, width, height, 0, NULL,
&error);
}
#else
backingStore = NULL;
image = create_image_2d(context, mem_flags, fmt, width, height, 0, NULL,
&error);
#endif
return error;
}
clProtectedImage::clProtectedImage(cl_context context, cl_mem_flags mem_flags,
const cl_image_format *fmt, size_t width,
size_t height, size_t depth,
cl_int *errcode_ret)
{
cl_int err = Create(context, mem_flags, fmt, width, height, depth);
if (errcode_ret != NULL) *errcode_ret = err;
}
cl_int clProtectedImage::Create(cl_context context, cl_mem_flags mem_flags,
const cl_image_format *fmt, size_t width,
size_t height, size_t depth)
{
cl_int error;
#if defined(__APPLE__)
int protect_pages = 1;
cl_device_id devices[16];
size_t number_of_devices;
error = clGetContextInfo(context, CL_CONTEXT_DEVICES, sizeof(devices),
devices, &number_of_devices);
test_error(error, "clGetContextInfo for CL_CONTEXT_DEVICES failed");
number_of_devices /= sizeof(cl_device_id);
for (int i = 0; i < (int)number_of_devices; i++)
{
cl_device_type type;
error = clGetDeviceInfo(devices[i], CL_DEVICE_TYPE, sizeof(type), &type,
NULL);
test_error(error, "clGetDeviceInfo for CL_DEVICE_TYPE failed");
if (type == CL_DEVICE_TYPE_GPU)
{
protect_pages = 0;
break;
}
}
if (protect_pages)
{
size_t pixelBytes = get_pixel_bytes(fmt);
size_t rowBytes = ROUND_SIZE_UP(width * pixelBytes, kPageSize);
size_t rowStride = rowBytes + kPageSize;
// create backing store
backingStoreSize = height * depth * rowStride + 8 * rowStride;
backingStore = mmap(0, backingStoreSize, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, 0, 0);
// add guard pages
size_t row;
char *p = (char *)backingStore;
char *imagePtr = (char *)backingStore + 4 * rowStride;
for (row = 0; row < 4; row++)
{
mprotect(p, rowStride, PROT_NONE);
p += rowStride;
}
p += rowBytes;
for (row = 0; row < height * depth; row++)
{
mprotect(p, kPageSize, PROT_NONE);
p += rowStride;
}
p -= rowBytes;
for (row = 0; row < 4; row++)
{
mprotect(p, rowStride, PROT_NONE);
p += rowStride;
}
if (getenv("CL_ALIGN_RIGHT"))
{
static int spewEnv = 1;
if (spewEnv)
{
log_info("***CL_ALIGN_RIGHT is set. Aligning images at right "
"edge of page\n");
spewEnv = 0;
}
imagePtr += rowBytes - pixelBytes * width;
}
image = create_image_3d(context, mem_flags | CL_MEM_USE_HOST_PTR, fmt,
width, height, depth, rowStride,
height * rowStride, imagePtr, &error);
}
else
{
backingStore = NULL;
image = create_image_3d(context, mem_flags, fmt, width, height, depth,
0, 0, NULL, &error);
}
#else
backingStore = NULL;
image = create_image_3d(context, mem_flags, fmt, width, height, depth, 0, 0,
NULL, &error);
#endif
return error;
}
clProtectedImage::clProtectedImage(cl_context context,
cl_mem_object_type imageType,
cl_mem_flags mem_flags,
const cl_image_format *fmt, size_t width,
size_t height, size_t depth,
size_t arraySize, cl_int *errcode_ret)
{
cl_int err = Create(context, imageType, mem_flags, fmt, width, height,
depth, arraySize);
if (errcode_ret != NULL) *errcode_ret = err;
}
cl_int clProtectedImage::Create(cl_context context,
cl_mem_object_type imageType,
cl_mem_flags mem_flags,
const cl_image_format *fmt, size_t width,
size_t height, size_t depth, size_t arraySize)
{
cl_int error;
#if defined(__APPLE__)
int protect_pages = 1;
cl_device_id devices[16];
size_t number_of_devices;
error = clGetContextInfo(context, CL_CONTEXT_DEVICES, sizeof(devices),
devices, &number_of_devices);
test_error(error, "clGetContextInfo for CL_CONTEXT_DEVICES failed");
number_of_devices /= sizeof(cl_device_id);
for (int i = 0; i < (int)number_of_devices; i++)
{
cl_device_type type;
error = clGetDeviceInfo(devices[i], CL_DEVICE_TYPE, sizeof(type), &type,
NULL);
test_error(error, "clGetDeviceInfo for CL_DEVICE_TYPE failed");
if (type == CL_DEVICE_TYPE_GPU)
{
protect_pages = 0;
break;
}
}
if (protect_pages)
{
size_t pixelBytes = get_pixel_bytes(fmt);
size_t rowBytes = ROUND_SIZE_UP(width * pixelBytes, kPageSize);
size_t rowStride = rowBytes + kPageSize;
// create backing store
switch (imageType)
{
case CL_MEM_OBJECT_IMAGE1D:
backingStoreSize = rowStride + 8 * rowStride;
break;
case CL_MEM_OBJECT_IMAGE2D:
backingStoreSize = height * rowStride + 8 * rowStride;
break;
case CL_MEM_OBJECT_IMAGE3D:
backingStoreSize = height * depth * rowStride + 8 * rowStride;
break;
case CL_MEM_OBJECT_IMAGE1D_ARRAY:
backingStoreSize = arraySize * rowStride + 8 * rowStride;
break;
case CL_MEM_OBJECT_IMAGE2D_ARRAY:
backingStoreSize =
height * arraySize * rowStride + 8 * rowStride;
break;
}
backingStore = mmap(0, backingStoreSize, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, 0, 0);
// add guard pages
size_t row;
char *p = (char *)backingStore;
char *imagePtr = (char *)backingStore + 4 * rowStride;
for (row = 0; row < 4; row++)
{
mprotect(p, rowStride, PROT_NONE);
p += rowStride;
}
p += rowBytes;
size_t sz = (height > 0 ? height : 1) * (depth > 0 ? depth : 1)
* (arraySize > 0 ? arraySize : 1);
for (row = 0; row < sz; row++)
{
mprotect(p, kPageSize, PROT_NONE);
p += rowStride;
}
p -= rowBytes;
for (row = 0; row < 4; row++)
{
mprotect(p, rowStride, PROT_NONE);
p += rowStride;
}
if (getenv("CL_ALIGN_RIGHT"))
{
static int spewEnv = 1;
if (spewEnv)
{
log_info("***CL_ALIGN_RIGHT is set. Aligning images at right "
"edge of page\n");
spewEnv = 0;
}
imagePtr += rowBytes - pixelBytes * width;
}
switch (imageType)
{
case CL_MEM_OBJECT_IMAGE1D:
image = create_image_1d(
context, mem_flags | CL_MEM_USE_HOST_PTR, fmt, width,
rowStride, imagePtr, NULL, &error);
break;
case CL_MEM_OBJECT_IMAGE2D:
image = create_image_2d(
context, mem_flags | CL_MEM_USE_HOST_PTR, fmt, width,
height, rowStride, imagePtr, &error);
break;
case CL_MEM_OBJECT_IMAGE3D:
image =
create_image_3d(context, mem_flags | CL_MEM_USE_HOST_PTR,
fmt, width, height, depth, rowStride,
height * rowStride, imagePtr, &error);
break;
case CL_MEM_OBJECT_IMAGE1D_ARRAY:
image = create_image_1d_array(
context, mem_flags | CL_MEM_USE_HOST_PTR, fmt, width,
arraySize, rowStride, rowStride, imagePtr, &error);
break;
case CL_MEM_OBJECT_IMAGE2D_ARRAY:
image = create_image_2d_array(
context, mem_flags | CL_MEM_USE_HOST_PTR, fmt, width,
height, arraySize, rowStride, height * rowStride, imagePtr,
&error);
break;
}
}
else
{
backingStore = NULL;
switch (imageType)
{
case CL_MEM_OBJECT_IMAGE1D:
image = create_image_1d(context, mem_flags, fmt, width, 0, NULL,
NULL, &error);
break;
case CL_MEM_OBJECT_IMAGE2D:
image = create_image_2d(context, mem_flags, fmt, width, height,
0, NULL, &error);
break;
case CL_MEM_OBJECT_IMAGE3D:
image = create_image_3d(context, mem_flags, fmt, width, height,
depth, 0, 0, NULL, &error);
break;
case CL_MEM_OBJECT_IMAGE1D_ARRAY:
image = create_image_1d_array(context, mem_flags, fmt, width,
arraySize, 0, 0, NULL, &error);
break;
case CL_MEM_OBJECT_IMAGE2D_ARRAY:
image = create_image_2d_array(context, mem_flags, fmt, width,
height, arraySize, 0, 0, NULL,
&error);
break;
}
}
#else
backingStore = NULL;
switch (imageType)
{
case CL_MEM_OBJECT_IMAGE1D:
image = create_image_1d(context, mem_flags, fmt, width, 0, NULL,
NULL, &error);
break;
case CL_MEM_OBJECT_IMAGE2D:
image = create_image_2d(context, mem_flags, fmt, width, height, 0,
NULL, &error);
break;
case CL_MEM_OBJECT_IMAGE3D:
image = create_image_3d(context, mem_flags, fmt, width, height,
depth, 0, 0, NULL, &error);
break;
case CL_MEM_OBJECT_IMAGE1D_ARRAY:
image = create_image_1d_array(context, mem_flags, fmt, width,
arraySize, 0, 0, NULL, &error);
break;
case CL_MEM_OBJECT_IMAGE2D_ARRAY:
image =
create_image_2d_array(context, mem_flags, fmt, width, height,
arraySize, 0, 0, NULL, &error);
break;
}
#endif
return error;
}
/*******
* clProtectedArray implementation
*******/
clProtectedArray::clProtectedArray() { mBuffer = mValidBuffer = NULL; }
clProtectedArray::clProtectedArray(size_t sizeInBytes)
{
mBuffer = mValidBuffer = NULL;
Allocate(sizeInBytes);
}
clProtectedArray::~clProtectedArray()
{
if (mBuffer != NULL)
{
#if defined(__APPLE__)
int error = munmap(mBuffer, mRealSize);
if (error) log_error("WARNING: munmap failed in clProtectedArray.\n");
#else
free(mBuffer);
#endif
}
}
void clProtectedArray::Allocate(size_t sizeInBytes)
{
#if defined(__APPLE__)
// Allocate enough space to: round up our actual allocation to an even
// number of pages and allocate two pages on either side
mRoundedSize = ROUND_SIZE_UP(sizeInBytes, kPageSize);
mRealSize = mRoundedSize + kPageSize * 2;
// Use mmap here to ensure we start on a page boundary, so the mprotect
// calls will work OK
mBuffer = (char *)mmap(0, mRealSize, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, 0, 0);
mValidBuffer = mBuffer + kPageSize;
// Protect guard area from access
mprotect(mValidBuffer - kPageSize, kPageSize, PROT_NONE);
mprotect(mValidBuffer + mRoundedSize, kPageSize, PROT_NONE);
#else
mRoundedSize = mRealSize = sizeInBytes;
mBuffer = mValidBuffer = (char *)calloc(1, mRealSize);
#endif
}