Могу ли я считывать данные пикселей из SDL_Texture после использования SDL_LockTexture()

#c #sdl #pixel #sdl-2

#c #sdl #пиксель #sdl-2

Вопрос:

Я работаю над функцией, которая «сопоставит» текстуру с целевой текстурой (где обе текстуры создаются с помощью подсказки SDL_TextureAccess «SDL_TEXTUREACCESS_STREAMING»). То есть, везде, где есть прозрачный пиксель (в частности, RGB все 255 и 0) на базовом изображении, соответствующий пиксель также будет сделан прозрачным на отображенном изображении. На изображении ниже показаны мои желаемые результаты (каждое изображение имеет размер 64×64 пикселя). Левая сторона без отображения.

Сравнительное Изображение

Первоначально я сделал это, просто используя SDL_Textures, и код для этого можно найти ниже (проверка ошибок опущена для краткости):

 void MapOntoTexture(SDL_Texture* base, SDL_Texture* mapped) {  Uint32 base_format = 0;  int height = 0;  SDL_QueryTexture(base, amp;base_format, NULL, NULL, amp;height);  SDL_PixelFormat* baseFormat = SDL_AllocFormat(base_format);    Uint32 mapped_format = 0;  int mappedHeight = 0;  SDL_QueryTexture(mapped, amp;mapped_format, NULL, NULL, amp;mappedHeight);  SDL_PixelFormat* mappedFormat = SDL_AllocFormat(mapped_format);    void* basePixels = NULL;  int basePitch = 0;  SDL_LockTexture(base, NULL, amp;basePixels, amp;basePitch);  Uint32* realBasePixels = basePixels;    void* mappedPixels = NULL;  int mappedPitch = 0;  SDL_LockTexture(mapped, NULL, amp;mappedPixels, amp;mappedPitch);  Uint32* realMappedPixels = mappedPixels;    int basePixelsInt = (basePitch / 4) * height;  int mappedPixelsInt = (mappedPitch / 4) * mappedHeight;  Uint32 baseTransparent = SDL_MapRGBA(baseFormat, 0xFF, 0xFF, 0xFF, 0x00);  Uint32 mappedTransparent = SDL_MapRGBA(mappedFormat, 0xFF, 0xFF, 0xFF, 0x00);    for(int i = 0; i lt; basePixelsInt; i  )  {  if (realBasePixels[i] == baseTransparent)  {  realMappedPixels[i] = mappedTransparent;  }  }    SDL_UnlockTexture(base);  SDL_UnlockTexture(mapped);    SDL_FreeFormat(baseFormat);  SDL_FreeFormat(mappedFormat); }  

Однако, перечитывая SDL-вики, я нашел эту цитату:

В качестве оптимизации пиксели, доступные для редактирования, не обязательно содержат старые данные текстуры. Это операция только для записи, и если вам нужно сохранить копию данных текстуры, вы должны сделать это на уровне приложения.

Часть, касающаяся только записи, касается меня, несмотря на то, что это работает в моей программе. Однако я подозреваю, что это случай неопределенного поведения демонов. Поэтому я написал другую функцию, которая вместо этого использует поверхности (а затем преобразует их в текстуры). Я признаю, что поверхности, возможно, потребуется заблокировать, и они указаны в фактическом коде, но опять же это опущено для краткости. Вот код:

 void MapOntoSurface(SDL_Surface* base, SDL_Surface* mapped) {  int basePixelsInt = (base-gt;pitch / 4) * base-gt;h;  int mappedPixelsInt = (mapped-gt;pitch / 4) * mapped-gt;h;  Uint32 baseTransparent = SDL_MapRGBA(base-gt;format, 0xFF, 0xFF, 0xFF, 0x00);  Uint32 mappedTransparent = SDL_MapRGBA(mapped-gt;format, 0xFF, 0xFF, 0xFF, 0x00);    Uint32* realBasePixels = base-gt;pixels;  Uint32* realMappedPixels = mapped-gt;pixels;    for(int i = 0; i lt; basePixelsInt; i  )  {  if (realBasePixels[i] == baseTransparent)  {  realMappedPixels[i] = mappedTransparent;  }  }    //Use "mapped" surface to create texture later }  

По общему признанию, это значительно проще, чем связанный с текстурой, но я бы предпочел этого не делать, так как это несколько неэлегантно, когда мне приходится преобразовывать поверхности в текстуры. Итак, наконец, мой вопрос: могу ли я использовать первую версию, не беспокоясь о неопределенном поведении, или мне следует использовать вторую?

Комментарии:

1. Как правило, в SDL операция записи на экран или текстуру является односторонней. Это означает, что вы генерируете пиксели, которые хотите записать, и выполняете запись (вывод на экран и т. Д.). Я так понимаю, это означает, что вы не можете ожидать, что будете считывать данные из области текстуры, которую вы изменили, чтобы восстановить те же данные. Таким образом, только запись и копирование на уровне приложения означает, что если вам нужно сохранить копию данных, которые вы собираетесь записать (для дальнейших изменений и т. Д.), Сделайте это, Не ожидайте, что вы прочитаете то, что вы написали для следующей модификации. (это мое «общее» понимание).

2. @David C. Рэнкин Итак, исходя из вашего понимания, вы бы сказали, что если бы я прочитал текстуру ровно один раз, то все было бы в порядке?

3. Насколько я понимаю, после записи в текстуру у вас нет гарантии, что вы сможете прочитать ту же информацию обратно. SDL может свободно обрабатывать память, связанную с текстурой, как скретч-панель после того, как сама текстура будет настроена для отображения. Вот почему у вас есть примечание о создании копии, если вам нужно сохранить то, что вы пишете. Я читал о SDL_QueryTexture() том, что он возвращает атрибуты текстуры, не обязательно каждого отдельного пикселя (это может быть, но не гарантировано-таким образом, копия). Я недостаточно занимаюсь SDL, чтобы быть авторитетом, но это мое прочтение записки.

4. Правильно, вы не считываете данные текстуры обратно. Как я вижу, заблокированное содержимое буфера сохраняется только в реализации средства визуализации opengl, и даже там оно может пойти не так, если вы объедините его с UpdateTexture . Кроме того, LockTexture используется только для потоковых текстур; все ли ваши текстуры помечены как потоковые? Если да, то понимаете ли вы, что это удваивает использование памяти в рендере opengl (единственном рендерере, кроме программного обеспечения, которое в настоящее время не удаляет заблокированные данные)? Это переназначение текстуры, которое вы делаете, — известно ли оно до программы lauch или динамично и может изменять каждый кадр?

5. @keltar Все мои текстуры созданы с флагом потоковой передачи (см. Редактирование). Я не понимал, что это удваивает использование памяти, но только текстуры, которые должны использовать эту функцию, создаются с флагом потоковой передачи (только небольшое количество текстур должно использовать эту функцию). Переназначение текстур известно до запуска программы, но если бы я создал все текстуры до запуска, у меня осталось бы дополнительно ~25000 дополнительных изображений для моей игры. Это была не та стоимость, которую я хотел переложить на своего пользователя.