Избежать потери результата при работе с CUDA и WInForms
Сделал проект на Win Forms, в Visual Studio вторым проектом сделал код на CUDA. Задумка - изображение с формы идет в CUDA, там обрабатывается и возвращается. Но тут пошли сложности - результат функции по идее должен записываться в переменную класса Image, и потом уже по этой переменной рисунок выводиться на форму, но... Visual Studio мне говорит - попытка обращения к защищенной памяти. Понятия не имею как обходить, думал и искал довольно долго. Как-то починить студию, исправить код или что надо, может в машине дело. Позже думаю переписать код чтобы с CUDA передавать обратно только число, не изображение, но заранее опасаюсь, что работать не будет. Код прилагаю ниже.
Первый кусок из самой формы, получаю функцию из библиотеки, потом вызываю и пытаюсь что-нибудь сделать, именно на последней строчке выкидывает ошибку. Если надо будет дополнить важной инфой, то пишите
HINSTANCE hGetProcIDDLL = LoadLibrary(L"CUDAWin.dll");
if (!hGetProcIDDLL)
{
throw gcnew Exception();
}
typedef int(__stdcall* function)(void*);
function calc = (function)GetProcAddress(hGetProcIDDLL, "calculate");
if (!calc)
{
throw gcnew Exception();
}
struct img* image = new img();
Bitmap^ bitmap = gcnew Bitmap(pct1->Image);
for (int j = 0; j < image->height; j++)
{
for (int i = 0; i < image->width; i++)
{
image->image[j * image->width + i] = bitmap -> GetPixel(i,j).ToArgb();
}
}
// Выполняем функцию из DLL библиотеки
image = (img*)calc((void*)image);
// Формируем результат для отображения в CLR компоненте
bitmap = gcnew Bitmap(image->width, image->height);
Отредактировал - не зашел с аккаунта, добавил код передачи, случайно его не вставил
Второй - сама уже функция на CUDA + принимающая, в которой и есть возврат результата.
CUDAWin.cpp
#include<windows.h>
#include "Kernel.cuh"
struct img
{
int width;
int height;
unsigned* image;
};
void* calculate(void* image)
{
struct img* im = (img*)image;
if (calc(im->image, im->width, im->height) == -1)
return NULL;
return im;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Kernel.cu
__global__ void kernel(unsigned* src, int width,
int height) {
int x = blockIdx.x * blockDim.x + threadIdx.x;
int y = blockIdx.y * blockDim.y + threadIdx.y;
if ((x < width) && (y < height))
{
unsigned pixel = src[y * width + x];
unsigned gray = ((pixel & 0x00FF0000 >> 0x10) +
(pixel & 0x0000FF00 >> 0x8) + (pixel & 0x000000FF))
/ 3;
src[y * width + x] = 0xFF000000 | (gray << 0x10) |
(gray << 0x8) | gray;
}
}
int calc(unsigned* srcImage, int width, int height)
{
unsigned* dev_srcImage;
size_t size = sizeof(unsigned) * width * height;
if (cudaMalloc((void**)&dev_srcImage, size) != cudaError::cudaSuccess)
return -1;
if (cudaMemcpy(dev_srcImage, srcImage, size, cudaMemcpyHostToDevice) != cudaError::cudaSuccess)
return -1;
// Максимальное количество нитей на блок может отличаться
dim3 threads(128, 128);
dim3 blocks((width + threads.x - 1) / threads.x, (height + threads.y - 1) / threads.y);
kernel << <threads, blocks >> > (dev_srcImage, width, height);
cudaError error = cudaMemcpy(srcImage, dev_srcImage, size, cudaMemcpyDeviceToHost);
if (error != cudaError::cudaSuccess) return -1;
cudaFree(dev_srcImage);
return 0;
}