Копируете данные цели рендеринга в D3DPOOL_MANAGED?

Я использую движок, использующий DirectX9.

Он создает цели рендеринга, используя:

D3DXCreateTexture(
    pD3DDevice, width, height, 1, 
    D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8, 
    D3DPOOL_DEFAULT, &pRT
)


И все остальные текстуры создаются так:

D3DXCreateTexture(
    pD3DDevice, width, height,
    1, 0, D3DFMT_A8R8G8B8,
    D3DPOOL_MANAGED, &pTex
)

Стоит отметить, что задний буфер тоже D3DFMT_X8R8G8B8, поэтому я не уверен, почему текстуры создаются по-другому... но я полагаю, "если он не сломан, не чините его", правильно? Все текстуры загружаются/отрисовываются нормально. Для получения более подробной информации о том, как работает этот движок, здесь его основной графический модуль code.
(в основном обратите внимание на методы Target_Create и Texture_Create)...

ОДНАКО, я столкнулся с массой проблем, пытаясь придерживаться этих правил, пытаясь преобразовать текстуру цели рендеринга в обычную текстуру. В движке нет для этого встроенных функций, а цели рендеринга обрабатываются как объекты, отдельные от текстур... И, в свою очередь, это ограничивает мою способность фактически ИСПОЛЬЗОВАТЬ все, что требует цели рендеринга (т.е. , пиксельные шейдеры и т. д.). Конечным результатом является то, что мне нужно найти способ скопировать эти данные цели рендеринга в текстуру, созданную, как указано выше, которую движок мог бы использовать без каких-либо конфликтов.

Я пробовал следующее:

inline PVOID LockedBits(LPDIRECT3DSURFACE9 surface, UINT w, UINT h, INT* size)
{
    D3DLOCKED_RECT lr;
    RECT rc = {0, 0, w, h};
    surface->LockRect(&lr, &rc, 0);
    if(size) *size = (w*h) * 4;
    return lr.pBits;
}
inline PVOID LockedBits(LPDIRECT3DTEXTURE9 texture, UINT w, UINT h, INT* size)
{
    D3DLOCKED_RECT lr;
    RECT rc = {0, 0, w, h};
    texture->LockRect(0, &lr, &rc, 0);
    if(size) *size = (w*h) * 4;
    return lr.pBits;
}

LPDIRECT3DTEXTURE9 CloneTextureFromTarget(LPDIRECT3DDEVICE9 device, LPDIRECT3DTEXTURE9 target, UINT w, UINT h)
{
    D3DDISPLAYMODE dm;
    device->GetDisplayMode(0, &dm);

    // Create source and destination surfaces and copy rendertarget
    LPDIRECT3DSURFACE9 dstSurf = NULL, srcSurf = NULL;
    device->CreateOffscreenPlainSurface(w, h, dm.Format, D3DPOOL_SYSTEMMEM, &dstSurf, NULL);
    target->GetSurfaceLevel(0, &srcSurf);
    device->GetRenderTargetData(srcSurf, dstSurf);
    SafeRelease(&srcSurf);

    // Create destination texture
    LPDIRECT3DTEXTURE9 dstTexture = NULL;
    D3DXCreateTexture(device, w, h, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &dstTexture);

    // Get bits for destination surface and texture
    INT dwSrc, dwDst;
    PVOID pBitsSrc = LockedBits(dstSurf, w, h, &dwSrc);
    PVOID pBitsDst = LockedBits(dstTexture, w, h, &dwDst);

    // Copy bits from surface to texture
    RtlCopyMemory(pBitsSrc, pBitsDst, dwSrc);
    dstTexture->UnlockRect(0);
    dstSurf->UnlockRect();
    SafeRelease(&dstSurf);

    /* Just to double-check if it worked... */
    D3DXSaveTextureToFileA("C:\\outSrc.png", D3DXIFF_PNG, target, NULL);
    D3DXSaveTextureToFileA("C:\\outDst.png", D3DXIFF_PNG, dstTexture, NULL);

    // Return the result
    return dstTexture;
}

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

Я делаю что-то неправильно? Каков наилучший способ добиться идеальной копии этих данных в новую текстуру, созданную с помощью D3DFMT_A8R8G8B8 и D3DPOOL_MANAGED?


person RectangleEquals    schedule 01.05.2013    source источник
comment
Вы можете создать цель рендеринга с помощью D3DFMT_A8R8G8B8, только задний буфер устройства должен быть создан с помощью D3DFMT_X8R8G8B8. Более того, этот rendertarget обычно можно использовать для рендеринга, но не для блокирующих операций. Нужна ли вам блокировка или вы хотите отрендерить цель рендеринга только в резервный буфер?   -  person Gnietschow    schedule 01.05.2013
comment
Если я создам его с помощью D3DFMT_A8R8G8B8, мне все равно потребуется средство для его удаления в новую текстуру D3DPOOL_MANAGED, поскольку я больше не буду использовать объект rendertarget и хотел бы освободить любые ресурсы, которые он использует. Движок обрабатывает текстуры и цели рендеринга как отдельные объекты, где цели рендеринга хранят/потребляют больше ресурсов... А для рендеринга мое приложение использует массив объектов текстуры, поэтому цель рендеринга просто используется во время инициализации для создания новых текстур (в пиксельном шейдере). ), чтобы добавить к этому массиву D3DPOOL_MANAGED текстур.   -  person RectangleEquals    schedule 01.05.2013
comment
Итак, что касается блокировки целевого объекта рендеринга... Пока я все еще могу (каким-то образом) клонировать его данные во вновь созданную текстуру D3DPOOL_MANAGED, тогда нет, поддержка блокировки не требуется... В противном случае да, требуется. Любая идея, как я могу безопасно клонировать эти данные в новую текстуру? Кроме того, приведенный выше код работает для вас? Для меня кажется, что изображение правильно сохраняется на диск, но почему-то не отображается в моем приложении.   -  person RectangleEquals    schedule 01.05.2013
comment
Я понятия не имею, почему ваш код не работает. Пробовали ли вы альтернативно работать с StretchRect, чтобы скопировать ваш rendertarget? В одном из моих приложений я использовал его для получения данных цели рендеринга, и он работал хорошо.   -  person Gnietschow    schedule 01.05.2013
comment
Согласно документации MSDN (раздел поддержки драйверов), вы не можете использовать StretchRect для перехода от текстуры RT к обычной текстуре. В обычную текстуру могут переходить только закадровые плоские текстуры, а копирование из RT в закадровый плайн даже не позволяет.   -  person RectangleEquals    schedule 02.05.2013
comment
Ой, кажется, я что-то там напутал. Вы говорите, что он сохраняет правильно, но не отображает. Вы рендерите с альфой? Возможно, этот канал был поврежден. Вы пробовали не очень хороший способ, чтобы сохранить результат на диск и загрузить его оттуда?   -  person Gnietschow    schedule 02.05.2013


Ответы (1)


TBH измените метод копирования следующим образом:

char* pSrc = (char*)pBitsSrc;
char* pDst = (char*)pBitsDst;
int p = 0;
int pMax = w * h;
while( p < pMax )
{
    // Copy B
    *pDst = *pSrc;
    pDst++;
    pSrc++;
    // Copy G
    *pDst = *pSrc;
    pDst++;
    pSrc++;
    // Copy R
    *pDst = *pSrc;
    pDst++;
    pSrc++;
    // Set A
    *pDst = 0xff;
    pDst++;
    pSrc++;
    p++;
}

Или, если это не удается, просто создайте целевую текстуру как D3DFMT_X8R8G8B8.

person Goz    schedule 09.05.2013