OpenCL void pointer аритметика - странно поведение

Написах OpenCL ядро, което използва оперативната съвместимост opencl-opengl за четене на върхове и индекси, но вероятно това дори не е важно, защото просто правя просто добавяне на указател, за да получа конкретен връх по индекс.

uint pos = (index + base)*stride;

Тук изчислявам абсолютната позиция в байтове, в моя пример pos е 28 643 328 със стъпка 28, индекс = 0 и основа = 1 022 976. Е, това изглежда правилно.

За съжаление, не мога да използвам vload3 директно, защото параметърът за отместване не се изчислява като абсолютен адрес в байтове. Така че просто добавям pos към показалеца void* vertices_gl

void* new_addr = vertices_gl+pos;

new_addr в моя пример е = 0x2f90000 и тук започва странната част,

vertices_gl = 0x303f000


Резултатът (new_addr) трябва да бъде 0x4B90000 (0x303f000 + 28,643,328)

Не разбирам защо адресът vertices_gl намалява със 716 800 (0xAF000)


Насочвам се към GPU: AMD Radeon HD5830

Ps: за тези, които се чудят, използвам printf, за да получа тези стойности :) (не можах да накарам CodeXL да работи)


person Aurus    schedule 16.06.2013    source източник
comment
На пръв поглед имам чувството, че трябва да е base + index * stride. Но освен това, не виждам нищо лошо тук, ако приемем, че vertices_gl е указател и аритметиката на указателя работи по същия начин в OpenCL, както и в C.   -  person Victor Zamanian    schedule 16.06.2013


Отговори (1)


Няма аритметика на указателя за void* указатели. Използвайте char* указатели, за да извършвате изчисления на указатели по байт.

Или много по-добре от това: Използвайте реалния тип, към който сочи указателят, и не умножавайте отместванията. Просто напишете vertex[index+base], като приемем, че vertex сочи към вашия тип, съдържащ 28 байта данни.

Съображение за производителността: Подравнете атрибутите на върховете си към степен две за обединен достъп до паметта. Това означава, добавете 4 байта подложка след всеки запис на върха. За да направите това автоматично, използвайте float8 като тип на върха, ако всичките ви атрибути са стойности с плаваща запетая. Предполагам, че работите с данни за позиция и нормални данни или нещо подобно, така че може да е добра идея да напишете персонализирана структура, която капсулира двата вектора по удобен и самообясняващ се начин:

// Defining a type for the vertex data. This is 32 bytes large.
// You can share this code in a header for inclusion in both OpenCL and C / C++!
typedef struct {
    float4 pos;
    float4 normal;
} VertexData;

// Example kernel
__kernel void computeNormalKernel(__global VertexData *vertex, uint base) {
    uint index = get_global_id(0);
    VertexData thisVertex = vertex[index+base];   // It can't be simpler!
    thisVertex.normal = computeNormal(...);       // Like you'd do it in C / C++!
    vertex[index+base] = thisVertex;              // Of couse also when writing
}

Забележка: Този код не работи с вашата крачка от 28, ако просто промените едно от float4s на float3, тъй като float3 също консумира 4 float памет. Но можете да го напишете така, което няма да добави подложка (но имайте предвид, че това ще накаже честотната лента за достъп до паметта):

typedef struct {
    float pos[4];
    float normal[3];  // Assuming you want 3 floats here
} VertexData;
person leemes    schedule 16.06.2013
comment
благодаря за отговора :) Но opengl прави ли някакво автоматично подравняване на буфера или нещо подобно? Сега използвам масив от тип връх, точно както казахте, но все още получавам грешни стойности.. Когато използвам VertexType vertex1 = vertices_gl[indices.x+base]; в OpenCL, получавам грешни стойности, но когато правя същото в моята C++ програма (използвайки необработения указател за същият буфер) получавам правилния резултат - person Aurus; 17.06.2013
comment
добре се оказа, че printf просто отпечатва грешни стойности :( - person Aurus; 17.06.2013
comment
Значи сега работи? Само запомнете: Когато подравнявате вашите атрибути, уверете се, че използвате същото подравняване на хоста, в OpenCL и в OpenGL. - person leemes; 17.06.2013