You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在DirectX11(低于11.1版本)下创建带完整Mipmaps的Texture2D

解决Windows 7 + DirectX 11环境下生成Mipmap的问题

首先得指出你代码里的一个关键错误:D3D11_USAGE_DEFAULT类型的资源不能设置D3D11_CPU_ACCESS_WRITE,这是DirectX 11的核心规则——DEFAULT资源是专门给GPU访问的,CPU无法直接写入,这个错误在任何DX11环境下都应该触发失败,只是DX12的规则更宽松才没报错。这也是你当前收到"Invalid arguments"错误的主要原因之一。

回到你的核心需求:在Windows 7(仅支持DX11)环境下生成Mipmap,因为无法使用D3D11_RESOURCE_MISC_GENERATE_MIPS标志(该特性需要DX11.1及以上),这里提供两种可行的替代方案:

方案一:使用Staging纹理作为中间载体 + D3DX11自动生成Mipmap

这是最简单的方案,如果你项目中可以链接D3DX11库的话:

  1. 创建Staging纹理:用来让CPU写入原始视频数据(Staging类型允许CPU读写)
  2. 创建带完整Mip层级的目标纹理:同时绑定Shader Resource和Render Target(DX11支持这种组合,只是不支持自动生成Mip的Misc标志)
  3. 复制数据到目标纹理的最高层级
  4. 调用D3DX11FilterTexture生成所有Mip层级

代码示例:

// 计算完整的Mip层级数
UINT calculateMipLevels(UINT width, UINT height)
{
    UINT levels = 1;
    while ((width > 1) || (height > 1))
    {
        width = max(1U, width / 2);
        height = max(1U, height / 2);
        levels++;
    }
    return levels;
}

// 1. 创建Staging纹理
D3D11_TEXTURE2D_DESC stagingDesc = {};
stagingDesc.Width = nWidth;
stagingDesc.Height = nHeight;
stagingDesc.MipLevels = 1;
stagingDesc.ArraySize = 1;
stagingDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
stagingDesc.SampleDesc.Count = 1;
stagingDesc.Usage = D3D11_USAGE_STAGING;
stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
stagingDesc.BindFlags = 0;
stagingDesc.MiscFlags = 0;

ID3D11Texture2D* pStagingTex = nullptr;
HRESULT hr = m_pD3dDevice->CreateTexture2D(&stagingDesc, nullptr, &pStagingTex);
if (FAILED(hr))
{
    // 处理创建失败
    return hr;
}

// 2. 写入视频数据到Staging纹理
D3D11_MAPPED_SUBRESOURCE mapped;
hr = m_pD3dContext->Map(pStagingTex, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
if (SUCCEEDED(hr))
{
    memcpy(mapped.pData, pYourVideoBuffer, nWidth * nHeight * 4); // 假设数据是RGBA8格式
    m_pD3dContext->Unmap(pStagingTex, 0);
}

// 3. 创建带完整Mip层级的目标纹理
UINT mipLevels = calculateMipLevels(nWidth, nHeight);
D3D11_TEXTURE2D_DESC targetDesc = {};
targetDesc.Width = nWidth;
targetDesc.Height = nHeight;
targetDesc.MipLevels = mipLevels;
targetDesc.ArraySize = 1;
targetDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
targetDesc.SampleDesc.Count = 1;
targetDesc.Usage = D3D11_USAGE_DEFAULT;
targetDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
targetDesc.CPUAccessFlags = 0;
targetDesc.MiscFlags = 0;

ID3D11Texture2D* pTargetTex = nullptr;
hr = m_pD3dDevice->CreateTexture2D(&targetDesc, nullptr, &pTargetTex);
if (FAILED(hr))
{
    pStagingTex->Release();
    return hr;
}

// 4. 复制Staging纹理数据到目标纹理的Mip Level 0
m_pD3dContext->CopySubresourceRegion(pTargetTex, 0, 0, 0, 0, pStagingTex, 0, nullptr);
pStagingTex->Release(); // 不再需要Staging纹理

// 5. 生成Mipmap(需要链接D3DX11.lib)
D3DX11FilterTexture(m_pD3dContext, pTargetTex, 0, D3DX11_DEFAULT);

// 后续可以创建Shader Resource View供Shader使用
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Format = targetDesc.Format;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = mipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;

ID3D11ShaderResourceView* pTexSRV = nullptr;
hr = m_pD3dDevice->CreateShaderResourceView(pTargetTex, &srvDesc, &pTexSRV);

方案二:手动渲染生成Mip层级(不依赖D3DX库)

如果你的项目不能使用D3DX库,可以手动通过渲染管线生成每个Mip层级:

  1. 按照方案一的步骤创建Staging纹理和目标纹理
  2. 复制数据到目标纹理的Mip Level 0
  3. 创建一个简单的全屏Pixel Shader,用来将上一层级的纹理缩小采样
  4. 为每个Mip层级创建对应的Render Target View(RTV),设置匹配的视口大小,绑定上一层级的Shader Resource View(SRV),渲染全屏三角形/四边形到当前RTV,完成缩小采样

核心代码片段(生成单个Mip层级):

// 假设已经创建了目标纹理pTargetTex和设备上下文m_pD3dContext
// 遍历每个Mip层级,从1开始到最高层级
for (UINT level = 1; level < mipLevels; level++)
{
    UINT prevWidth = max(1U, nWidth / (UINT)pow(2, level-1));
    UINT prevHeight = max(1U, nHeight / (UINT)pow(2, level-1));
    UINT currWidth = max(1U, prevWidth / 2);
    UINT currHeight = max(1U, prevHeight / 2);

    // 创建当前层级的RTV
    D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
    rtvDesc.Format = targetDesc.Format;
    rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
    rtvDesc.Texture2D.MipSlice = level;

    ID3D11RenderTargetView* pCurrRTV = nullptr;
    m_pD3dDevice->CreateRenderTargetView(pTargetTex, &rtvDesc, &pCurrRTV);

    // 创建上一层级的SRV
    D3D11_SHADER_RESOURCE_VIEW_DESC prevSrvDesc = {};
    prevSrvDesc.Format = targetDesc.Format;
    prevSrvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
    prevSrvDesc.Texture2D.MipLevels = 1;
    prevSrvDesc.Texture2D.MostDetailedMip = level-1;

    ID3D11ShaderResourceView* pPrevSRV = nullptr;
    m_pD3dDevice->CreateShaderResourceView(pTargetTex, &prevSrvDesc, &pPrevSRV);

    // 设置视口
    D3D11_VIEWPORT vp = {};
    vp.Width = (FLOAT)currWidth;
    vp.Height = (FLOAT)currHeight;
    vp.MinDepth = 0.0f;
    vp.MaxDepth = 1.0f;
    m_pD3dContext->RSSetViewports(1, &vp);

    // 绑定RTV和SRV
    m_pD3dContext->OMSetRenderTargets(1, &pCurrRTV, nullptr);
    m_pD3dContext->PSSetShaderResources(0, 1, &pPrevSRV);

    // 渲染全屏三角形(这里假设你已经有对应的Vertex Shader和Input Layout)
    m_pD3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    m_pD3dContext->Draw(3, 0);

    // 释放资源
    pCurrRTV->Release();
    pPrevSRV->Release();
}

这个方案需要你提前准备好全屏渲染的基础管线(Vertex Shader、Input Layout等),但好处是完全不依赖第三方库,兼容性更好。


内容的提问来源于stack exchange,提问作者RustOnce

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:24:43