XV. Interopérabilité avec DirectX▲
Des ressources Direct3D peuvent être utilisées avec CUDA, pour que CUDA puisse lire ces données pour les traiter, ou bien pour que CUDA puisse écrire des données qui seront utilisées par Direct3D.
CUDA peut fonctionner avec les versions 9.0 et 10.0 de Direct3D. Pour la première, les fonctions sont préfixées par cudaD3D9. Pour la seconde, par cudaD3D10. C'est le seul élément qui change entre les deux fonctions (à part le fait qu'elles ne sont pas utilisées avec les mêmes versions de D3D). C'est pourquoi je ne préciserai que les fonctions pour D3D9.
Cependant, tout ne peut pas fonctionner comme vous le désirez, mais ces restrictions restent très logiques. Un contexte CUDA ne peut communiquer qu'avec un seul périphérique D3D à la fois et ils doivent correspondre au même GPU. De plus, le périphérique D3D doit être créé avec le drapeau D3DCREATE_HARDWARE_VERTEXPROCESSING.
if
(
NULL
==
(
g_pD3D =
Direct3DCreate9
(
D3D_SDK_VERSION ) ) )
return
E_FAIL;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory
(
&
d3dpp, sizeof
(
d3dpp) );
d3dpp.Windowed =
TRUE;
d3dpp.BackBufferCount =
1
;
d3dpp.SwapEffect =
D3DSWAPEFFECT_COPY;
d3dpp.hDeviceWindow =
g_handles.hwndText;
d3dpp.BackBufferWidth =
IMAGE_SIZE_X;
d3dpp.BackBufferHeight =
IMAGE_SIZE_Y;
d3dpp.BackBufferFormat =
D3DFMT_UNKNOWN;
d3dpp.PresentationInterval =
D3DPRESENT_INTERVAL_IMMEDIATE;
hr =
g_pD3D->
CreateDevice (
adapter, D3DDEVTYPE_HAL, g_handles.hwndCGH,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
&
d3dpp, &
g_pD3DDevice);
if
(
FAILED
(
hr ) )
return
hr;
cudaD3D9SetDirect3DDevice
(
g_pD3DDevice);
La fonction cudaD3D9SetDirect3DDevice() doit être appelée avant toute autre fonction de CUDA !
Pour associer une ressource DirectX à CUDA, cudaD3D9RegisterResource() est utilisé.
IDirect3DVertexBuffer9 *
vbuffer;
cudaD3D9RegisterResource
(
vbuffer, cudaD3D9RegisterFlagsNone);
IDirect3DSurface9 *
surface;
cudaD3D9RegisterResource
(
surface, cudaD3D9RegisterFlagsNone);
ID3D9Buffer *
buffer;
cudaD3D9RegisterResource
(
buffer, cudaD3D9RegisterFlagsNone);
ID3D9Texture2D*
tex2D
;
cudaD3D9RegisterResource
(
tex2D
, cudaD3D9RegisterFlagsNone);
Vous pouvez désenregistrer les ressources grâce à cudaD3D9UnregisterVertexBuffer()
cudaD3D9UnregisterVertexBuffer
(
vbuffer);
cudaD3D9UnregisterVertexBuffer
(
surface);
cudaD3D9UnregisterVertexBuffer
(
buffer);
cudaD3D9UnregisterVertexBuffer
(
tex2D
);
Dès qu'une ressource est enregistrée, vous pouvez la lier avec cudaD3D9MapResources() et la délier avec cudaD3D9UnmapResources(). Dès qu'elle est liée, vous pouvez l'utiliser dans un kernel. Pour ce faire, vous aurez besoin de son adresse, retournée par cudaD3D9ResourceGetMappedPointer(). Si vous accédez à une ressource liée par D3D, les résultats sont indéfinis.
ID3D9Buffer *
buffer;
cudaD3D9RegisterResource
(
buffer, cudaD3D9RegisterFlagsNone);
void
*
devPtr;
cudaD3D9ResourceGetMappedPointer
(&
devPtr, buffer, 0
, 0
);
size_t size;
cudaD3D9ResourceGetMappedSize
(&
size, buffer, 0
, 0
);
cudaMemset
(
devPtr, 0
, size);
Dans ce dernier exemple, chaque thread accède à un pixel de la surface 2D.
void
*
devPtr;
cudaD3D9ResourceGetMappedPointer
(&
devPtr, surface, 0
, 0
);
size_t pitch;
cudaD3D9ResourceGetMappedPitch
(&
pitch, 0
, surface, 0
, 0
);
dim3
Db =
dim3
(
16
, 16
);
dim3
Dg =
dim3
(
(
width+
Db.x-
1
) /
Db.x, (
height+
Db.y-
1
) /
Db.y);
mykernel <<<
Dg, Db >>>
(
(
unsigned
char
*
) devPtr, width, height, pitch);
__global__
void
mykernel
(
unsigned
char
*
surface,
int
width, int
height, size_t pitch)
{
int
x =
blockIdx
.x *
blockDim
.x +
threadIdx
.x;
int
y =
blockIdx
.y *
blockDim
.y +
threadIdx
.y;
if
(
x >=
width ||
y >=
height) return
;
float
*
pixel =
(
float
*
) (
surface +
y *
pitch) +
4
*
x;
}
XVI. Interopérabilité avec OpenGL▲
Des ressources OpenGL peuvent être utilisées avec CUDA, pour que CUDA puisse lire ces données pour les traiter, ou bien pour que CUDA puisse écrire des données qui seront utilisées par OpenGL.
Tout comme Direct3D, la fonction cudaGLSetGLDevice() doit être appelée avant toutes les autres fonctions CUDA.
Un buffer peut être enregistré avec la fonction cudaGLRegisterBufferObject() et lié avec cudaGLMapBufferObject().
Vous pouvez délier avec cudaGLUnmapBufferObject() et désenregistrer avec cudaGLUnregisterBufferObject()
GLuint bufferObj;
cudaGLRegisterBufferObject
(
bufferObj);
float
*
devPtr;
cudaGLMapBufferObject
(
(
void
**
) &
devPtr, bufferObj);