diff --git a/projects/clr/opencl/tests/ocltst/env/ServiceCode.cpp b/projects/clr/opencl/tests/ocltst/env/ServiceCode.cpp new file mode 100644 index 0000000000..f83137819c --- /dev/null +++ b/projects/clr/opencl/tests/ocltst/env/ServiceCode.cpp @@ -0,0 +1,330 @@ +/* Copyright (c) 2010 - 2021 Advanced Micro Devices, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. */ + +#include +#define CL_USE_DEPRECATED_OPENCL_2_0_APIS 1 +#include "CL/cl.hpp" + +SERVICE_STATUS serviceStatus = {0}; +SERVICE_STATUS_HANDLE serviceStatusHandle = 0; + +const wchar_t* CrossProcessEventName = L"Global\\OpenCL_Test_serviceEvent"; +const wchar_t* successMessage = L"OpenCL Service Test Success\n"; +const wchar_t* serviceName = L"OpenCL Test service"; +// this event is set whenever the service thread is finished executing +// all it's tasks +HANDLE RetireServiceEvent = 0; + +DWORD WINAPI ThreadProc(LPVOID lpdwThreadParam); + +////////////////////////// +// log relate functions // +////////////////////////// +void getLogFileName(wchar_t fileName[MAX_PATH]) { + DWORD dwSize = GetModuleFileNameW(NULL, fileName, MAX_PATH); + wchar_t* p = fileName + dwSize; + while (*p != '\\' && p > fileName) p--; + p++; + wcscpy(p, L"result.txt"); +} + +VOID WriteLog(const wchar_t* pMsg) { + static wchar_t fileName[MAX_PATH] = {0}; + if (fileName[0] == 0) getLogFileName(fileName); + + FILE* pLog = _wfopen(fileName, L"w"); + if (NULL != pLog) { + fwprintf(pLog, pMsg); + fclose(pLog); + } +} + +VOID AppendLog(const wchar_t* pMsg) { + static wchar_t fileName[MAX_PATH] = {0}; + if (fileName[0] == 0) getLogFileName(fileName); + FILE* pLog = _wfopen(fileName, L"a"); + if (NULL != pLog) { + fwprintf(pLog, pMsg); + fclose(pLog); + } +} + +VOID AppendLog(const char* pMsg) { + static wchar_t fileName[MAX_PATH] = {0}; + if (fileName[0] == 0) getLogFileName(fileName); + FILE* pLog = _wfopen(fileName, L"a"); + if (NULL != pLog) { + fprintf(pLog, pMsg); + fclose(pLog); + } +} +/////////////////////////////// +// service related functions // +/////////////////////////////// +void WINAPI ServiceControlHandler(DWORD controlCode) { + switch (controlCode) { + case SERVICE_CONTROL_INTERROGATE: + break; + + case SERVICE_CONTROL_SHUTDOWN: + case SERVICE_CONTROL_STOP: + serviceStatus.dwCurrentState = SERVICE_STOP_PENDING; + if (!SetServiceStatus(serviceStatusHandle, &serviceStatus)) + AppendLog(L"SetServiceStatus SERVICE_STOP_PENDING failed\n"); + + if (RetireServiceEvent) SetEvent(RetireServiceEvent); + return; + + case SERVICE_CONTROL_PAUSE: + break; + + case SERVICE_CONTROL_CONTINUE: + break; + + default: + if (controlCode >= 128 && controlCode <= 255) + // user defined control code + break; + else + // unrecognised control code + break; + } + + if (!SetServiceStatus(serviceStatusHandle, &serviceStatus)) + AppendLog(L"SetServiceStatus SERVICE_STOP_PENDING failed\n"); +} + +void WINAPI ServiceMain(DWORD /*argc*/, wchar_t* /*argv*/[]) { + // initialise service status + serviceStatus.dwServiceType = SERVICE_WIN32; + serviceStatus.dwCurrentState = SERVICE_START_PENDING; + serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN; + serviceStatus.dwWin32ExitCode = NO_ERROR; + serviceStatus.dwServiceSpecificExitCode = NO_ERROR; + serviceStatus.dwCheckPoint = 0; + serviceStatus.dwWaitHint = 0; + + serviceStatusHandle = + RegisterServiceCtrlHandlerW(serviceName, ServiceControlHandler); + + if (serviceStatusHandle) { + // service is starting + serviceStatus.dwCurrentState = SERVICE_START_PENDING; + if (!SetServiceStatus(serviceStatusHandle, &serviceStatus)) + AppendLog(L"SetServiceStatus SERVICE_START_PENDING failed\n"); + + // do initialisation here + RetireServiceEvent = CreateEvent(0, FALSE, FALSE, 0); + + // running + serviceStatus.dwControlsAccepted |= + (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + serviceStatus.dwCurrentState = SERVICE_RUNNING; + if (!SetServiceStatus(serviceStatusHandle, &serviceStatus)) + AppendLog(L"SetServiceStatus SERVICE_RUNNING failed\n"); + + // Create the thread that actually does the CL testing + CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL); + // wait for the thread to finish + WaitForSingleObject(RetireServiceEvent, 60000); + + HANDLE crossProcessEvent = + OpenEventW(EVENT_ALL_ACCESS, FALSE, CrossProcessEventName); + if (NULL != crossProcessEvent) { + SetEvent(crossProcessEvent); + } else { + AppendLog(L"cross process Event could not be openned\n"); + } + + // service was stopped + serviceStatus.dwCurrentState = SERVICE_STOP_PENDING; + if (!SetServiceStatus(serviceStatusHandle, &serviceStatus)) + AppendLog(L"SetServiceStatus SERVICE_STOP_PENDING failed\n"); + + // do cleanup here + CloseHandle(crossProcessEvent); + CloseHandle(RetireServiceEvent); + RetireServiceEvent = 0; + + // service is now stopped + serviceStatus.dwControlsAccepted &= + ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + serviceStatus.dwCurrentState = SERVICE_STOPPED; + if (!SetServiceStatus(serviceStatusHandle, &serviceStatus)) + AppendLog(L"SetServiceStatus SERVICE_STOPPED failed\n"); + } +} + +// This function services ocltst as a service when launched +// by the OS. It registers the service routines. +void serviceStubCall() { + wchar_t serviceName[MAX_PATH]; + wcscpy(serviceName, ::serviceName); + SERVICE_TABLE_ENTRYW serviceTable[] = {{serviceName, ServiceMain}, {0, 0}}; + DWORD session_id; + BOOL retVal = ProcessIdToSessionId(GetCurrentProcessId(), &session_id); + if (0 == session_id) { + StartServiceCtrlDispatcherW(serviceTable); + } +} +///////////////////// +// CL related code // +///////////////////// +const char c_kernelCode[] = + " __kernel void hello(__global char * theArray)" + "{" + " size_t i = get_global_id(0);" + "if ( i < get_global_size(0))" + "theArray[i] = 78;" + "}"; + +const unsigned int c_bufferSize = 1024; + +DWORD WINAPI ThreadProc(LPVOID lpdwThreadParam) { + cl_int err; + // Platform info + std::vector platforms; + + err = cl::Platform::get(&platforms); + if (err != CL_SUCCESS) { + AppendLog(L"Platform::get() failed\n"); + return -1; + } + + std::vector::iterator i; + if (platforms.size() > 0) { + for (i = platforms.begin(); i != platforms.end(); ++i) { + if (!strcmp((*i).getInfo(&err).c_str(), + "Advanced Micro Devices, Inc.")) { + break; + } + } + } + if (err != CL_SUCCESS) { + AppendLog(L"Platform::getInfo() failed \n"); + return -1; + } + + cl_context_properties cps[3] = {CL_CONTEXT_PLATFORM, + (cl_context_properties)(*i)(), 0}; + + cl::Context context(CL_DEVICE_TYPE_GPU, cps, NULL, NULL, &err); + if (err != CL_SUCCESS) { + AppendLog(L"Context::Context() failed \n"); + return -1; + } + + std::vector devices = context.getInfo(); + if (err != CL_SUCCESS) { + AppendLog(L"Context::getInfo() failed \n"); + return -1; + } + if (devices.size() == 0) { + AppendLog(L"No device available\n"); + return -1; + } + + cl::Program::Sources sources( + 1, std::make_pair(c_kernelCode, sizeof(c_kernelCode))); + + cl::Program program = cl::Program(context, sources, &err); + if (err != CL_SUCCESS) { + AppendLog(L"Program::Program() failed\n"); + } + + err = program.build(devices); + if (err != CL_SUCCESS) { + if (err == CL_BUILD_PROGRAM_FAILURE) { + std::string str( + (char*)program.getBuildInfo(devices[0]) + .c_str()); + + AppendLog(L" \n\t\t\tBUILD LOG\n\n"); + AppendLog(L" ************************************************\n"); + AppendLog(str.c_str()); + AppendLog(L" ************************************************\n"); + } + + AppendLog(L"Program::build() failed\n"); + return -1; + } + + cl::Kernel kernel(program, "hello", &err); + if (err != CL_SUCCESS) { + AppendLog(L"Kernel::Kernel() failed\n"); + return -1; + } + + cl::Buffer buffer = + cl::Buffer(context, CL_MEM_READ_WRITE, c_bufferSize, 0, &err); + if (err != CL_SUCCESS) { + AppendLog(L"Kernel::setArg() failed \n"); + } + + cl::CommandQueue queue(context, devices[0], 0, &err); + if (err != CL_SUCCESS) { + AppendLog(L"CommandQueue::CommandQueue() failed \n"); + return -1; + } + + err = kernel.setArg(0, buffer); + if (err != CL_SUCCESS) { + AppendLog(L"Kernel::setArg() failed \n"); + return -1; + } + + err = queue.enqueueNDRangeKernel(kernel, cl::NullRange, + cl::NDRange(c_bufferSize), cl::NullRange); + + if (err != CL_SUCCESS) { + AppendLog(L"CommandQueue::enqueueNDRangeKernel()\n"); + return -1; + } + + err = queue.finish(); + if (err != CL_SUCCESS) { + AppendLog(L"Event::wait() failed \n"); + } + char* ptr = (char*)malloc(c_bufferSize); + err = queue.enqueueReadBuffer(buffer, CL_TRUE, 0, c_bufferSize, ptr, NULL, + NULL); + if (err != CL_SUCCESS) { + AppendLog(L"CommandQueue::enqueueReadBuffer()\n"); + return -1; + } + + bool validateSuccess = true; + // validate the results + for (int i = 0; i < c_bufferSize; i++) { + if (ptr[i] != 78) validateSuccess = false; + } + + free(ptr); + if (validateSuccess) { + WriteLog(successMessage); + AppendLog(L"validate success"); + } else { + AppendLog(L"Validate fail"); + return -1; + } + + SetEvent(RetireServiceEvent); + return 0; +} diff --git a/projects/clr/opencl/tests/ocltst/env/getopt.cpp b/projects/clr/opencl/tests/ocltst/env/getopt.cpp new file mode 100644 index 0000000000..9964b93a71 --- /dev/null +++ b/projects/clr/opencl/tests/ocltst/env/getopt.cpp @@ -0,0 +1,48 @@ +/* Copyright (c) 2010 - 2021 Advanced Micro Devices, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. */ + +#include "getopt.h" + +#include + +char *optarg = nullptr; +int optind = 1; + +int getopt(int argc, char *const argv[], const char *optstring) { + if ((optind >= argc) || (argv[optind][0] != '-') || (argv[optind][0] == 0)) { + return -1; + } + + int opt = argv[optind][1]; + const char *p = strchr(optstring, opt); + + if (p == nullptr) { + return '?'; + } + if (p[1] == ':') { + optind++; + if (optind >= argc) { + return '?'; + } + optarg = argv[optind]; + optind++; + } + return opt; +} diff --git a/projects/clr/opencl/tests/ocltst/env/getopt.h b/projects/clr/opencl/tests/ocltst/env/getopt.h new file mode 100644 index 0000000000..18ef649b60 --- /dev/null +++ b/projects/clr/opencl/tests/ocltst/env/getopt.h @@ -0,0 +1,26 @@ +/* Copyright (c) 2010 - 2021 Advanced Micro Devices, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. */ + +#pragma once + +extern char *optarg; +extern int optind; + +extern "C" int getopt(int argc, char *const argv[], const char *optstring); diff --git a/projects/clr/opencl/tests/ocltst/env/window.cpp b/projects/clr/opencl/tests/ocltst/env/window.cpp new file mode 100644 index 0000000000..1f6b669100 --- /dev/null +++ b/projects/clr/opencl/tests/ocltst/env/window.cpp @@ -0,0 +1,175 @@ +/* Copyright (c) 2010 - 2021 Advanced Micro Devices, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. */ + +#ifdef ATI_OS_WIN + +#include +#include +#include + +#include "Window.h" + +HWND Window::_hWnd; +unsigned char* Window::_data; +unsigned int Window::_w; +unsigned int Window::_h; + +void Window::OnPaint(void) { + PAINTSTRUCT ps; + HDC hDC = BeginPaint(_hWnd, &ps); + + if (_w && _h && _data) { + BITMAPINFO bm; + bm.bmiColors[0].rgbBlue = 0; + bm.bmiColors[0].rgbGreen = 0; + bm.bmiColors[0].rgbRed = 0; + bm.bmiColors[0].rgbReserved = 0; + + bm.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bm.bmiHeader.biWidth = _w; + bm.bmiHeader.biHeight = _h; + bm.bmiHeader.biPlanes = 1; + bm.bmiHeader.biBitCount = 32; + bm.bmiHeader.biCompression = BI_RGB; + bm.bmiHeader.biSizeImage = 0; + bm.bmiHeader.biXPelsPerMeter = 0; + bm.bmiHeader.biYPelsPerMeter = 0; + bm.bmiHeader.biClrUsed = 0; + bm.bmiHeader.biClrImportant = 0; + + int ret = SetDIBitsToDevice(hDC, 0, 0, _w, _h, 0, 0, 0, _h, _data, &bm, + DIB_RGB_COLORS); + assert(ret); + } + + EndPaint(_hWnd, &ps); +} + +/***************************************************************************** + *****************************************************************************/ +LRESULT WINAPI Window::DefWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, + LPARAM lParam) { + switch (uMsg) { + case WM_CHAR: + switch (wParam) { + case 27: // ESC + exit(0); + break; + } + return 0; + case WM_PAINT: + OnPaint(); + return 0; + } + return ::DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +Window::Window(const char* title, int x, int y, int width, int height, + unsigned int uiStyle) { + _data = NULL; + _w = 0; + _h = 0; + + WNDCLASS wc = {0, + (WNDPROC)Window::DefWindowProc, + 0, + 0, + GetModuleHandle(0), + LoadIcon(NULL, IDI_WINLOGO), + LoadCursor(NULL, IDC_ARROW), + NULL, + NULL, + "TST"}; + if (!RegisterClass(&wc)) { + MessageBox(NULL, "RegisterClass() failed", "Error", MB_OK); + exit(0); + } + + if (uiStyle == 0) { + uiStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + } + + RECT r = {x, y, x + width, y + height}; + AdjustWindowRect(&r, uiStyle, 0); + + _hWnd = CreateWindow("TST", title, uiStyle, r.left, r.top, r.right - r.left, + r.bottom - r.top, NULL, NULL, GetModuleHandle(0), this); + if (_hWnd == NULL) { + MessageBox(NULL, "CreateWindow() failed.", "Error", MB_OK); + exit(0); + } + + ShowWindow(_hWnd, SW_SHOW); + UpdateWindow(_hWnd); +} + +Window::~Window(void) { + DestroyWindow(_hWnd); + + if (_data) { + delete[] _data; + } + + UnregisterClass("TST", GetModuleHandle(NULL)); +} + +void Window::ConsumeEvents(void) { + while (1) { + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { + GetMessage(&msg, NULL, 0, 0); + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } +} + +void Window::ShowImage(unsigned int width, unsigned int height, float* data) { + if (_data) { + delete[] _data; + } + + _data = new unsigned char[4 * width * height]; + _w = width; + _h = height; + + unsigned char* pb = _data; + float* p = data; + unsigned int i; + for (i = 0; i < (unsigned int)(width * height); i++) { + // + // argb + // + float v = p[2] > 1.f ? 1.f : (p[2] < 0.f ? 0.f : p[2]); + *pb++ = (unsigned char)(255.f * v); + v = p[1] > 1.f ? 1.f : (p[1] < 0.f ? 0.f : p[1]); + *pb++ = (unsigned char)(255.f * v); + v = p[0] > 1.f ? 1.f : (p[0] < 0.f ? 0.f : p[0]); + *pb++ = (unsigned char)(255.f * v); + v = p[3] > 1.f ? 1.f : (p[3] < 0.f ? 0.f : p[3]); + *pb++ = (unsigned char)(255.f * v); + p += 4; + } + + RedrawWindow(_hWnd, NULL, NULL, RDW_INVALIDATE); + OnPaint(); +} + +#endif // ATI_OS_WIN diff --git a/projects/clr/opencl/tests/ocltst/env/window.h b/projects/clr/opencl/tests/ocltst/env/window.h new file mode 100644 index 0000000000..0936c61e7e --- /dev/null +++ b/projects/clr/opencl/tests/ocltst/env/window.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2010 - 2021 Advanced Micro Devices, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. */ + +#ifndef _WINDOW_H_ +#define _WINDOW_H_ + +#ifdef ATI_OS_WIN + +#include +#include + +class Window { + public: + typedef LRESULT (*WindowProc)(HWND hW, UINT uMsg, WPARAM wP, LPARAM lP); + + public: + Window(const char* title, int x, int y, int width, int height, + unsigned int uiStyle); + ~Window(); + + void ConsumeEvents(void); + void ShowImage(unsigned int width, unsigned int height, float* data); + + private: + static LRESULT WINAPI DefWindowProc(HWND hW, UINT uMsg, WPARAM wP, LPARAM lP); + + static void OnPaint(void); + + public: + static HWND _hWnd; + static unsigned char* _data; + static unsigned int _w; + static unsigned int _h; +}; + +#endif // ATI_OS_WIN + +#endif // _WINDOW_H_