针对上篇提到的,渲染过程中有很多对象不需要每次都设置一遍,今天测试了一下,确实是这样。
另外我记得看采样器的时候有提到,采样器可以做缩放的,之前一直不成功,原来是viewPort的原因,忘了当初为啥要这么写了...
那么最新的逻辑是,顶点着色器,像素着色器和ShaderResourceView都在初始化阶段创建并设置进管线里,之后用copyResource将资源拷贝到m_outputImage里既可。
const Vertex vertices[] = {
{-1, 1, 0, 0, 0},
{1, 1, 0, 1, 0},
{1, -1, 0, 1, 1},
{-1, -1, 0, 0, 1},
};
const UINT16 indices[] = {
0,1,2, 0,2,3
};
D3D11_BUFFER_DESC bd = {};
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.ByteWidth = sizeof(vertices);
bd.StructureByteStride = sizeof(Vertex);
D3D11_SUBRESOURCE_DATA sd = {};
sd.pSysMem = vertices;
this->m_device->CreateBuffer(&bd, &sd, &this->m_pVertexBuffer);
D3D11_BUFFER_DESC ibd = {};
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
ibd.ByteWidth = sizeof(indices);
ibd.StructureByteStride = sizeof(UINT16);
D3D11_SUBRESOURCE_DATA isd = {};
isd.pSysMem = indices;
this->m_device->CreateBuffer(&ibd, &isd, &this->m_pIndexBuffer);
// 新增: 初始化方法中创建Texture与shaderResourceView
D3D11_TEXTURE2D_DESC tdesc;
ZeroMemory(&tdesc, sizeof(D3D11_TEXTURE2D_DESC));
tdesc.Width = this->width();
tdesc.Height = this->height();
tdesc.MipLevels = 1;
tdesc.ArraySize = 1;
tdesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
tdesc.SampleDesc.Count = 1;
tdesc.SampleDesc.Quality = 0;
tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
tdesc.CPUAccessFlags = 0;
tdesc.MiscFlags = 0;
hr = this->m_device->CreateTexture2D(&tdesc, nullptr, &this->m_outputImage);
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = CD3D11_SHADER_RESOURCE_VIEW_DESC(
this->m_outputImage,
D3D11_SRV_DIMENSION_TEXTURE2D,
DXGI_FORMAT_B8G8R8A8_UNORM
);
hr = this->m_device->CreateShaderResourceView(this->m_outputImage, &srvDesc, &this->m_srv);
// 顶点着色器
D3D11_INPUT_ELEMENT_DESC ied[] = {
{"POSITION", 0, DXGI_FORMAT::DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"TEXCOORD", 0, DXGI_FORMAT::DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}
};
hr = this->m_device->CreateInputLayout(ied, std::size(ied), g_main, sizeof(g_main), &this->m_pInputLayout);
hr = this->m_device->CreateVertexShader(g_main, sizeof(g_main), nullptr, &this->m_pVertexShader);
D3D11_SAMPLER_DESC samplerDesc = {};
samplerDesc.Filter = D3D11_FILTER::D3D11_FILTER_ANISOTROPIC;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.MaxAnisotropy = 16;
hr = this->m_device->CreateSamplerState(&samplerDesc, &this->m_pSampler);
// 像素着色器
hr = this->m_device->CreatePixelShader(g_main_PS, sizeof(g_main_PS), nullptr, &this->m_pPixelShader);
hr = S_OK;
// 新增: 将原来渲染里的设置着色器、缓存那些移到初始化方法中
UINT stride = sizeof(Vertex);
UINT offset = 0u;
this->m_context->IASetVertexBuffers(0, 1, &this->m_pVertexBuffer, &stride, &offset);
this->m_context->IASetIndexBuffer(this->m_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
this->m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY::D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
this->m_context->IASetInputLayout(this->m_pInputLayout);
this->m_context->VSSetShader(this->m_pVertexShader, 0, 0);
this->m_context->PSSetShader(this->m_pPixelShader, 0, 0);
ID3D11ShaderResourceView* srvs[] = { this->m_srv };
this->m_context->PSSetShaderResources(0, 1, srvs);
ID3D11SamplerState* samplers[] = { this->m_pSampler };
this->m_context->PSSetSamplers(0, 1, samplers);
渲染中只需要进行绘制
const UINT16 indices[] = {
0,1,2, 0,2,3
};
auto indicesSize = std::size(indices);
this->m_context->DrawIndexed(indicesSize, 0, 0);
this->m_swapChain->Present(0, 0);
这里直接用copyResource将资源拷贝到我们之前创建的texture里
void copy_to_render_texture(uint8_t* _buffer, ID3D11Texture2D* _texture)
{
if (this->m_outputImage != nullptr) {
this->m_context->CopyResource(this->m_outputImage, _texture);
}
}
每次渲染就不需要像之前那样创建那么多资源了。
TODO
下一步优化代码结构,与渲染相关的部分移到窗口类中,通过纹理共享句柄进行跨设备拷贝。也就是在创建纹理时将D3D11_TEXTURE2D_DESC的MiscFlags设置为D3D11_RESOURCE_MISC_SHARED。
D3D11_RESOURCE_MISC_SHARED
值: 0x2L
启用两个或多个 Direct3D 设备之间的资源数据共享。 唯一可以共享的资源是 2D 非误入式纹理。
D3D11_RESOURCE_MISC_SHARED 和 D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX 是相互排斥的。
WARP 和 REF 设备不支持共享资源。
如果尝试在 WARP 或 REF 设备上使用此标志创建资源,create 方法将返回 E_OUTOFMEMORY 错误代码。