简体   繁体   English

dx9 和 dx11 mipmap 的区别

[英]difference between dx9 and dx11 mipmaps

I had tried to generate mipmaps for both DX9 and DX11 in same way, i needed them to sample specific levels from pixel shader.我曾尝试以相同的方式为 DX9 和 DX11 生成 mipmap,我需要它们从像素着色器中采样特定级别。 After that i noticed that sampling is different on different DX versions, and seems to be worse with DX11 and good with DX9.之后我注意到不同 DX 版本的采样不同,DX11 似乎更差,DX9 更好。

Next i tried to visualize it by rendering a backbuffer copy image and 4x downscaled size with ImGui and the results were:接下来,我尝试通过使用 ImGui 渲染后缓冲复制图像和 4 倍缩小尺寸来将其可视化,结果是:

DX9 with mipmaps generation: dx9 w mips DX9 与 mipmaps 生成: dx9 w mips

DX9 without mipmaps generation: dx9 wo mips没有生成 mipmap 的 DX9: dx9 wo mips

DX11 with mipmaps generation: dx11 w mips DX11 与 mipmaps 生成: dx11 w mips

DX11 without mipmaps generation: dx11 wo mips没有生成 mipmap 的 DX11: dx11 wo mips

The texture creation is absolutely same:纹理创建是完全一样的:

DX9 DX9

static IDirect3DTexture9* pBackBufferResource = nullptr;

IDirect3DSurface9* pBackBuffer = nullptr;
g_pd3dDevice->GetBackBuffer(0U, 0U, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);

D3DSURFACE_DESC descBack = { };
pBackBuffer->GetDesc(&descBack);

if (pBackBufferResource == nullptr)
{
    g_pd3dDevice->CreateTexture(descBack.Width, descBack.Height, 1U, D3DUSAGE_RENDERTARGET | D3DUSAGE_AUTOGENMIPMAP, descBack.Format, D3DPOOL_DEFAULT, &pBackBufferResource, nullptr);

    /*
     * explicitly set linear filter for mipmap generation
     * for some reason 'D3DSAMP_MIPFILTER' sampler state doesn't actually change this
     */
    pBackBufferResource->SetAutoGenFilterType(D3DTEXF_LINEAR);
}

// get the most detailed mip-level surface
IDirect3DSurface9* pResourceTopSurface = nullptr;
pBackBufferResource->GetSurfaceLevel(0U, &pResourceTopSurface);

// because backbuffer haven't mipmap, we couldn't just copy its texture, we're update only most detailed mip-level
g_pd3dDevice->StretchRect(pBackBuffer, nullptr, pResourceTopSurface, nullptr, D3DTEXF_LINEAR);

// the 'D3DUSAGE_AUTOGENMIPMAP' flag of texture creation will regenerate mipmap automatically, but here do it manually just for sure
pBackBufferResource->GenerateMipSubLevels();

ImVec2 vecMin = { 10.f, 10.f };
ImVec2 vecMax = { vecMin.x + floorf((float)descBack.Width / 4.0f), vecMin.y + floorf((float)descBack.Height / 4.0f) };
ImGui::GetForegroundDrawList()->AddImage(pBackBufferResource, vecMin, vecMax);
ImGui::GetForegroundDrawList()->AddRect(vecMin, vecMax, IM_COL32(0, 0, 0, 255));

DX11 DX11

static ID3D11Texture2D* pBackBufferCopy = nullptr;
static ID3D11ShaderResourceView* pBackBufferResource = nullptr;

ID3D11Texture2D* pBackBuffer = nullptr;
g_mainRenderTargetView->GetResource(reinterpret_cast<ID3D11Resource**>(&pBackBuffer));

D3D11_TEXTURE2D_DESC descBack = { };
pBackBuffer->GetDesc(&descBack);

if (pBackBufferCopy == nullptr)
{
    D3D11_TEXTURE2D_DESC descBackCopy = descBack;
    descBackCopy.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
    descBackCopy.MipLevels = 0U;
    descBackCopy.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;
    g_pd3dDevice->CreateTexture2D(&descBackCopy, nullptr, &pBackBufferCopy);
}

// because backbuffer haven't mipmap, we couldn't copy its texture just with 'CopyResource()', so we're update only most detailed mip-level
g_pd3dDeviceContext->CopySubresourceRegion(pBackBufferCopy, 0U, 0U, 0U, 0U, pBackBuffer, 0U, nullptr);

pBackBuffer->Release();

if (pBackBufferResource == nullptr)
{
    D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDescBuffer = { };
    resourceViewDescBuffer.Format = descBack.Format;
    resourceViewDescBuffer.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
    resourceViewDescBuffer.Texture2D.MostDetailedMip = 0U;
    resourceViewDescBuffer.Texture2D.MipLevels = ~0U;
    g_pd3dDevice->CreateShaderResourceView(pBackBufferCopy, &resourceViewDescBuffer, &pBackBufferResource);
}

// regenerate mipmap based on updated most detailed mip-level
g_pd3dDeviceContext->GenerateMips(pBackBufferResource);

ImVec2 vecMin = { 10.f, 10.f };
ImVec2 vecMax = { vecMin.x + floorf((float)descBack.Width / 4.0f), vecMin.y + floorf((float)descBack.Height / 4.0f) };
ImGui::GetForegroundDrawList()->AddImage(pBackBufferResource, vecMin, vecMax);
ImGui::GetForegroundDrawList()->AddRect(vecMin, vecMax, IM_COL32(0, 0, 0, 255));

Sampler states of MIN/MAG/MIP filters are LINEAR and MaxLOD is D3D11_FLOAT32_MAX for both renderers.两个渲染器的 MIN/MAG/MIP 过滤器的采样器状态为 LINEAR,MaxLOD 为 D3D11_FLOAT32_MAX。 It's clear that DX11 image are excessively sharp and looking same w/ and w/o mipmaps.很明显,DX11 图像过于清晰,并且在使用和不使用 mipmap 时看起来都一样。 So my question is why it happens with DX11 and doesn't happens with DX9, when i'm sure that it does generate mipmaps properly and i can sample from them inside shader (shader sampling is also looking sharper)?所以我的问题是为什么它会发生在 DX11 上而不会发生在 DX9 上,当我确定它确实会正确生成 mipmap 并且我可以在着色器中从它们中采样(着色器采样也看起来更清晰)?

The general answer is that auto-generated mipmips is left entirely up to the driver.一般的答案是自动生成的 mipmips 完全由驱动程序决定。 As such, the quality of auto-generated mips is going vary widely from driver to driver, and in some cases for some formats it can be as low-quality as point-sampling.因此,自动生成的 mip 的质量因驱动程序而异,在某些情况下,对于某些格式,它的质量可能与点采样一样低。

This is in fact one of the reasons that DirectX 12 doesn't have 'auto-generated mips' as a feature.这实际上是 DirectX 12 没有“自动生成的 mips”功能的原因之一。 Instead if you need this feature, the recommendation is to use a compute shader.相反,如果您需要此功能,建议使用计算着色器。 For an example, see DirectX Tool Kit for DX12 .有关示例,请参阅适用于 DX12 的 DirectX 工具包

All that said, you need to validate all functions that return HRESULT values as you are likely getting an error code back somewhere you are ignoring.话虽如此,您需要验证所有返回HRESULT值的函数,因为您可能会在您忽略的某个地方返回错误代码。 For example, I doubt that calling SetAutoGenFilterType on a swapchain buffer actually does what you think it does.例如,我怀疑在交换链缓冲区上调用SetAutoGenFilterType是否真的如你所想。 Even if you just treat them as fail fast , don't ignore HRESULT returns.即使您只是将它们视为快速失败,也不要忽略HRESULT返回。

For DirectX 11, you should enable the debug device and look for output.对于 DirectX 11,您应该启用调试设备并查找输出。 Since DirectX 9 is legacy, the 'debug device' for it has not been supported since Windows 7.由于 DirectX 9 是旧版,因此自 Windows 7 起不再支持它的“调试设备”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM