Арифметика пустого указателя OpenCL - странное поведение

Я написал ядро ​​OpenCL, которое использует совместимость opencl-opengl для чтения вершин и индексов, но, вероятно, это даже не важно, потому что я просто выполняю простое добавление указателя, чтобы получить конкретную вершину по индексу.

uint pos = (index + base)*stride;

Здесь я вычисляю абсолютную позицию в байтах, в моем примере pos — это 28 643 328 с шагом 28, index = 0 и base = 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* для выполнения побайтовых вычислений указателя.

Или намного лучше: используйте тип real, на который указывает указатель, и не умножайте смещения. Просто напишите 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, если вы просто измените один из float4 на float3, поскольку float3 также потребляет 4 числа с плавающей запятой памяти. Но вы можете написать это так, что не добавит заполнения (но обратите внимание, что это будет штрафовать пропускную способность доступа к памяти):

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