2013-04-18 03:09:55 +00:00
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
2010-02-19 17:05:26 +00:00
2011-02-14 02:18:03 +00:00
// TODO: Make a more centralized version of this (for now every backend that will use it will create its own context, which is weird). An object maybe?
2010-02-19 17:05:26 +00:00
# include "OpenCL.h"
# include "Common.h"
# include "Timer.h"
namespace OpenCL
{
cl_device_id device_id = NULL ;
cl_context g_context = NULL ;
cl_command_queue g_cmdq = NULL ;
bool g_bInitialized = false ;
bool Initialize ( )
{
if ( g_bInitialized )
return true ;
if ( g_context )
return false ;
2010-06-29 10:23:40 +00:00
int err ; // error code returned from api calls
2010-06-29 02:23:09 +00:00
2010-12-05 16:57:32 +00:00
# ifdef __APPLE__
// If OpenCL is weakly linked and not found, its symbols will be NULL
if ( clGetPlatformIDs = = NULL )
return false ;
# else
2010-06-29 10:23:40 +00:00
clrInit ( ) ;
if ( ! clrHasOpenCL ( ) )
return false ;
2010-06-29 02:23:09 +00:00
# endif
2010-02-19 17:05:26 +00:00
// Connect to a compute device
cl_uint numPlatforms ;
cl_platform_id platform = NULL ;
err = clGetPlatformIDs ( 0 , NULL , & numPlatforms ) ;
if ( err ! = CL_SUCCESS )
{
HandleCLError ( err , " clGetPlatformIDs failed. " ) ;
return false ;
}
2010-07-06 13:14:51 +00:00
if ( 0 < numPlatforms )
2010-02-19 17:05:26 +00:00
{
cl_platform_id * platforms = new cl_platform_id [ numPlatforms ] ;
err = clGetPlatformIDs ( numPlatforms , platforms , NULL ) ;
if ( err ! = CL_SUCCESS )
{
HandleCLError ( err , " clGetPlatformIDs failed. " ) ;
return false ;
}
char pbuf [ 100 ] ;
2010-12-05 09:04:34 +00:00
err = clGetPlatformInfo ( platforms [ 0 ] , CL_PLATFORM_VENDOR , sizeof ( pbuf ) ,
pbuf , NULL ) ;
2010-02-19 17:05:26 +00:00
if ( err ! = CL_SUCCESS )
{
HandleCLError ( err , " clGetPlatformInfo failed. " ) ;
return false ;
}
platform = platforms [ 0 ] ;
delete [ ] platforms ;
}
else
{
PanicAlert ( " No OpenCL platform found. " ) ;
return false ;
}
2010-12-05 09:04:34 +00:00
cl_context_properties cps [ 3 ] = { CL_CONTEXT_PLATFORM ,
( cl_context_properties ) platform , 0 } ;
2010-02-19 17:05:26 +00:00
cl_context_properties * cprops = ( NULL = = platform ) ? NULL : cps ;
2010-05-30 08:08:26 +00:00
err = clGetDeviceIDs ( platform , CL_DEVICE_TYPE_DEFAULT , 1 , & device_id , NULL ) ;
2010-02-19 17:05:26 +00:00
if ( err ! = CL_SUCCESS )
{
HandleCLError ( err , " Failed to create a device group! " ) ;
return false ;
}
2010-07-06 13:14:51 +00:00
// Create a compute context
2010-02-19 17:05:26 +00:00
g_context = clCreateContext ( cprops , 1 , & device_id , NULL , NULL , & err ) ;
if ( ! g_context )
{
HandleCLError ( err , " Failed to create a compute context! " ) ;
return false ;
}
// Create a command commands
g_cmdq = clCreateCommandQueue ( g_context , device_id , 0 , & err ) ;
if ( ! g_cmdq )
{
HandleCLError ( err , " Failed to create a command commands! " ) ;
return false ;
}
g_bInitialized = true ;
return true ;
}
cl_context GetContext ( )
{
return g_context ;
}
cl_command_queue GetCommandQueue ( )
{
return g_cmdq ;
}
cl_program CompileProgram ( const char * Kernel )
{
u32 compileStart = Common : : Timer : : GetTimeMs ( ) ;
2010-12-05 09:04:34 +00:00
cl_int err ;
2010-02-19 17:05:26 +00:00
cl_program program ;
2010-12-05 09:04:34 +00:00
program = clCreateProgramWithSource ( OpenCL : : g_context , 1 ,
( const char * * ) & Kernel , NULL , & err ) ;
2010-12-19 11:03:09 +00:00
2010-02-19 17:05:26 +00:00
if ( ! program )
{
HandleCLError ( err , " Error: Failed to create compute program! " ) ;
}
// Build the program executable
err = clBuildProgram ( program , 0 , NULL , NULL , NULL , NULL ) ;
if ( err ! = CL_SUCCESS ) {
2013-03-20 01:51:12 +00:00
HandleCLError ( err , " Error: failed to build program " ) ;
2010-12-18 04:54:16 +00:00
char * buildlog = NULL ;
2013-03-20 01:51:12 +00:00
size_t buildlog_size = 0 ;
2010-12-18 04:54:16 +00:00
clGetProgramBuildInfo ( program , OpenCL : : device_id , CL_PROGRAM_BUILD_LOG , 0 , NULL , & buildlog_size ) ;
2013-03-20 01:51:12 +00:00
buildlog = new char [ buildlog_size + 1 ] ;
err = clGetProgramBuildInfo ( program , OpenCL : : device_id , CL_PROGRAM_BUILD_LOG , buildlog_size , buildlog , NULL ) ;
buildlog [ buildlog_size ] = 0 ;
2013-10-29 05:23:17 +00:00
2013-03-20 01:51:12 +00:00
if ( err ! = CL_SUCCESS )
{
HandleCLError ( err , " Error: can't get build log " ) ;
} else
{
ERROR_LOG ( COMMON , " Error log: \n %s \n " , buildlog ) ;
}
delete [ ] buildlog ;
2010-02-19 17:05:26 +00:00
return NULL ;
}
2010-12-19 11:03:09 +00:00
INFO_LOG ( COMMON , " OpenCL CompileProgram took %.3f seconds " ,
2010-12-05 09:04:34 +00:00
( float ) ( Common : : Timer : : GetTimeMs ( ) - compileStart ) / 1000.0 ) ;
2010-02-19 17:05:26 +00:00
return program ;
}
cl_kernel CompileKernel ( cl_program program , const char * Function )
{
u32 compileStart = Common : : Timer : : GetTimeMs ( ) ;
int err ;
// Create the compute kernel in the program we wish to run
cl_kernel kernel = clCreateKernel ( program , Function , & err ) ;
if ( ! kernel | | err ! = CL_SUCCESS )
{
2010-07-06 13:14:51 +00:00
char buffer [ 1024 ] ;
sprintf ( buffer , " Failed to create compute kernel '%s' ! " , Function ) ;
2010-06-22 03:10:43 +00:00
HandleCLError ( err , buffer ) ;
2010-02-19 17:05:26 +00:00
return NULL ;
}
2010-12-19 11:03:09 +00:00
INFO_LOG ( COMMON , " OpenCL CompileKernel took %.3f seconds " ,
2010-12-05 09:04:34 +00:00
( float ) ( Common : : Timer : : GetTimeMs ( ) - compileStart ) / 1000.0 ) ;
2010-02-19 17:05:26 +00:00
return kernel ;
}
void Destroy ( )
{
2010-10-24 04:17:36 +00:00
if ( g_cmdq )
{
clReleaseCommandQueue ( g_cmdq ) ;
g_cmdq = NULL ;
}
if ( g_context )
{
clReleaseContext ( g_context ) ;
g_context = NULL ;
2013-10-29 05:23:17 +00:00
}
2010-02-19 17:05:26 +00:00
g_bInitialized = false ;
}
2010-05-26 22:40:06 +00:00
void HandleCLError ( cl_int error , const char * str )
2010-02-19 17:05:26 +00:00
{
2010-05-26 22:40:06 +00:00
const char * name ;
2010-02-19 17:05:26 +00:00
switch ( error )
{
# define CL_ERROR(x) case (x): name = #x; break
CL_ERROR ( CL_SUCCESS ) ;
CL_ERROR ( CL_DEVICE_NOT_FOUND ) ;
CL_ERROR ( CL_DEVICE_NOT_AVAILABLE ) ;
CL_ERROR ( CL_COMPILER_NOT_AVAILABLE ) ;
CL_ERROR ( CL_MEM_OBJECT_ALLOCATION_FAILURE ) ;
CL_ERROR ( CL_OUT_OF_RESOURCES ) ;
CL_ERROR ( CL_OUT_OF_HOST_MEMORY ) ;
CL_ERROR ( CL_PROFILING_INFO_NOT_AVAILABLE ) ;
CL_ERROR ( CL_MEM_COPY_OVERLAP ) ;
CL_ERROR ( CL_IMAGE_FORMAT_MISMATCH ) ;
CL_ERROR ( CL_IMAGE_FORMAT_NOT_SUPPORTED ) ;
CL_ERROR ( CL_BUILD_PROGRAM_FAILURE ) ;
CL_ERROR ( CL_MAP_FAILURE ) ;
CL_ERROR ( CL_INVALID_VALUE ) ;
CL_ERROR ( CL_INVALID_DEVICE_TYPE ) ;
CL_ERROR ( CL_INVALID_PLATFORM ) ;
CL_ERROR ( CL_INVALID_DEVICE ) ;
CL_ERROR ( CL_INVALID_CONTEXT ) ;
CL_ERROR ( CL_INVALID_QUEUE_PROPERTIES ) ;
CL_ERROR ( CL_INVALID_COMMAND_QUEUE ) ;
CL_ERROR ( CL_INVALID_HOST_PTR ) ;
CL_ERROR ( CL_INVALID_MEM_OBJECT ) ;
CL_ERROR ( CL_INVALID_IMAGE_FORMAT_DESCRIPTOR ) ;
CL_ERROR ( CL_INVALID_IMAGE_SIZE ) ;
CL_ERROR ( CL_INVALID_SAMPLER ) ;
CL_ERROR ( CL_INVALID_BINARY ) ;
CL_ERROR ( CL_INVALID_BUILD_OPTIONS ) ;
CL_ERROR ( CL_INVALID_PROGRAM ) ;
CL_ERROR ( CL_INVALID_PROGRAM_EXECUTABLE ) ;
CL_ERROR ( CL_INVALID_KERNEL_NAME ) ;
CL_ERROR ( CL_INVALID_KERNEL_DEFINITION ) ;
CL_ERROR ( CL_INVALID_KERNEL ) ;
CL_ERROR ( CL_INVALID_ARG_INDEX ) ;
CL_ERROR ( CL_INVALID_ARG_VALUE ) ;
CL_ERROR ( CL_INVALID_ARG_SIZE ) ;
CL_ERROR ( CL_INVALID_KERNEL_ARGS ) ;
CL_ERROR ( CL_INVALID_WORK_DIMENSION ) ;
CL_ERROR ( CL_INVALID_WORK_GROUP_SIZE ) ;
CL_ERROR ( CL_INVALID_WORK_ITEM_SIZE ) ;
CL_ERROR ( CL_INVALID_GLOBAL_OFFSET ) ;
CL_ERROR ( CL_INVALID_EVENT_WAIT_LIST ) ;
CL_ERROR ( CL_INVALID_EVENT ) ;
CL_ERROR ( CL_INVALID_OPERATION ) ;
CL_ERROR ( CL_INVALID_GL_OBJECT ) ;
CL_ERROR ( CL_INVALID_BUFFER_SIZE ) ;
CL_ERROR ( CL_INVALID_MIP_LEVEL ) ;
# undef CL_ERROR
default :
name = " Unknown error code " ;
}
if ( ! str )
str = " " ;
ERROR_LOG ( COMMON , " OpenCL error: %s %s (%d) " , str , name , error ) ;
}
}