首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Directx11实现DXT压缩纹理的错误运行时更新

用Directx11实现DXT压缩纹理的错误运行时更新
EN

Stack Overflow用户
提问于 2016-06-17 15:56:05
回答 1查看 1.3K关注 0票数 0

上下文:,我正在开发一个原生的C++统一5插件,它读取DXT压缩的纹理数据,并将其上传到GPU,以便在统一中进一步使用。其目的是创建一个快速的图像序列播放器,实时更新图像数据.使用脱机控制台应用程序压缩纹理。统一可以使用不同的图形引擎,我的目标是DirectX11和OpenGL 3.3+。

问题:运行时纹理更新代码,通过映射的子资源,在不同的图形驱动程序上提供不同的输出。通过这样的映射资源更新纹理意味着将指针映射到纹理数据,并将数据从RAM缓冲器映射到映射的GPU缓冲区。这样做,不同的驱动程序在复制字节时,似乎对行间距值期望不同的参数。我从来没有问题的几个Nvidia GPU的测试,但AMD和英特尔GPU似乎采取不同的行动,我得到扭曲的输出,如下图所示。此外,我正在处理DXT1像素数据(0.5bpp)和DXT5数据(1bpp)。我似乎无法得到这些DXT纹理的正确的音调参数.

代码:以下初始化代码,用于生成d3d11纹理并填充初始纹理数据--例如,图像序列的第一帧--对所有驱动程序都是完美的。播放机指针指向一个自定义类,该类处理当前加载的DXT压缩帧的所有文件读取和包含getter,以及它的尺寸等。

代码语言:javascript
复制
if (s_DeviceType == kUnityGfxRendererD3D11)
    {
        HRESULT hr;
        DXGI_FORMAT format = (compression_type == DxtCompressionType::DXT_TYPE_DXT1_NO_ALPHA) ? DXGI_FORMAT_BC1_UNORM : DXGI_FORMAT_BC3_UNORM;

        // Create texture
        D3D11_TEXTURE2D_DESC desc;
        desc.Width = w;
        desc.Height = h;
        desc.MipLevels = 1;
        desc.ArraySize = 1;
        desc.Format = format;
        // no anti-aliasing
        desc.SampleDesc.Count = 1;
        desc.SampleDesc.Quality = 0;
        desc.Usage = D3D11_USAGE_DYNAMIC;
        desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
        desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
        desc.MiscFlags = 0;

        // Initial data: first frame
        D3D11_SUBRESOURCE_DATA data;
        data.pSysMem = player->getBufferPtr();
        data.SysMemPitch = 16 * (player->getWidth() / 4);
        data.SysMemSlicePitch = 0; // just a 2d texture, no depth

        // Init with initial data
        hr = g_D3D11Device->CreateTexture2D(&desc, &data, &dxt_d3d_tex);

        if (SUCCEEDED(hr) && dxt_d3d_tex != 0)
        {
            DXT_VERBOSE("Succesfully created D3D Texture.");

            DXT_VERBOSE("Creating D3D SRV.");
            D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
            memset(&SRVDesc, 0, sizeof(SRVDesc));
            SRVDesc.Format = format;
            SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
            SRVDesc.Texture2D.MipLevels = 1;

            hr = g_D3D11Device->CreateShaderResourceView(dxt_d3d_tex, &SRVDesc, &textureView);
            if (FAILED(hr))
            {
                dxt_d3d_tex->Release();
                return hr;
            }
            DXT_VERBOSE("Succesfully created D3D SRV.");
        }
        else
        {
            DXT_ERROR("Error creating D3D texture.")
        }
    }

以下为每个新帧运行的更新代码在某个地方出现错误。请注意,包含方法1的注释行使用一个简单的memcpy,没有指定任何行距,这对NVIDIA驱动程序很有效。

您可以在方法2中进一步看到,我记录了不同的行间距值。例如,对于1920x960帧,缓冲器步长为1920,运行时步长为2048。这128个像素的差异可能需要填充(如下面的示例图所示),但我不知道如何填充。当我只使用mappedResource.RowPitch而不将它除以4(由位移位完成)时,团结就会崩溃。

代码语言:javascript
复制
    ID3D11DeviceContext* ctx = NULL;
    g_D3D11Device->GetImmediateContext(&ctx);

    if (dxt_d3d_tex && bShouldUpload)
    {
        if (player->gather_stats) before_upload = ns();

        D3D11_MAPPED_SUBRESOURCE mappedResource;
        ctx->Map(dxt_d3d_tex, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);

        /* 1: THIS CODE WORKS ON ALL NVIDIA DRIVERS BUT GENERATES DISTORTED OR NO OUTPUT ON AMD/INTEL: */
        //memcpy(mappedResource.pData, player->getBufferPtr(), player->getBytesPerFrame());

        /* 2: THIS CODE GENERATES OUTPUT BUT SEEMS TO NEED PADDING? */
        BYTE* mappedData = reinterpret_cast<BYTE*>(mappedResource.pData);
        BYTE* buffer = player->getBufferPtr();
        UINT height = player->getHeight();
        UINT buffer_stride = player->getBytesPerFrame() / player->getHeight();
        UINT runtime_stride = mappedResource.RowPitch >> 2;

        DXT_VERBOSE("Buffer stride: %d", buffer_stride);
        DXT_VERBOSE("Runtime stride: %d", runtime_stride);

        for (UINT i = 0; i < height; ++i)
        {
            memcpy(mappedData, buffer, buffer_stride);
            mappedData += runtime_stride;
            buffer += buffer_stride;
        }

        ctx->Unmap(dxt_d3d_tex, 0);
    }

示例图1 -当使用memcpy复制整个缓冲区而不使用AMD/INTEL上的单独行间距时失真的输出(方法1)

示例pic 2 -当在AMD/INTEL上使用上面的mappedResource.RowPitch代码时,输出效果更好,但仍然是错误的(方法2)。蓝色条形表示错误区域,需要消失,所以所有像素都很好地对齐,形成一幅图像。

谢谢你的指点!最好,文森特

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-06-19 04:32:19

映射的数据行间距是以字节为单位的,如果除以4,则肯定是一个问题。

代码语言:javascript
复制
UINT runtime_stride = mappedResource.RowPitch >> 2;
...
mappedData += runtime_stride; // here you are only jumping one quarter of a row

它是一个BC格式的高度计数除以4。

另外,BC1格式是每4x4块8字节,所以下面的行应该是8 *而不是16 *,但是只要您正确地处理行,d3d就会理解,您在这里浪费了一半的内存。

代码语言:javascript
复制
data.SysMemPitch = 16 * (player->getWidth() / 4);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37885775

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档