blob: 49a08b9d96202168706ad62382ed71b867ef8f31 [file] [log] [blame]
// Copyright 2017 The NXT Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "backend/d3d12/TextureD3D12.h"
#include "backend/d3d12/D3D12Backend.h"
#include "backend/d3d12/ResourceAllocator.h"
namespace backend {
namespace d3d12 {
namespace {
D3D12_RESOURCE_STATES D3D12TextureUsage(nxt::TextureUsageBit usage, nxt::TextureFormat format) {
D3D12_RESOURCE_STATES resourceState = D3D12_RESOURCE_STATE_COMMON;
if (usage & nxt::TextureUsageBit::TransferSrc) {
resourceState |= D3D12_RESOURCE_STATE_COPY_SOURCE;
}
if (usage & nxt::TextureUsageBit::TransferDst) {
resourceState |= D3D12_RESOURCE_STATE_COPY_DEST;
}
if (usage & nxt::TextureUsageBit::Sampled) {
resourceState |= (D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
}
if (usage & nxt::TextureUsageBit::Storage) {
resourceState |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
}
if (usage & nxt::TextureUsageBit::OutputAttachment) {
resourceState |= D3D12_RESOURCE_STATE_RENDER_TARGET;
if (TextureBase::IsDepthFormat(format)) {
resourceState |= D3D12_RESOURCE_STATE_DEPTH_WRITE;
}
}
return resourceState;
}
D3D12_RESOURCE_FLAGS D3D12ResourceFlags(nxt::TextureUsageBit usage, nxt::TextureFormat format) {
D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE;
if (usage & nxt::TextureUsageBit::Storage) {
flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
}
if (usage & nxt::TextureUsageBit::OutputAttachment) {
flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
if (TextureBase::IsDepthFormat(format)) {
flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
}
}
return flags;
}
D3D12_RESOURCE_DIMENSION D3D12TextureDimension(nxt::TextureDimension dimension) {
switch (dimension) {
case nxt::TextureDimension::e2D:
return D3D12_RESOURCE_DIMENSION_TEXTURE2D;
default:
UNREACHABLE();
}
}
DXGI_FORMAT D3D12TextureFormat(nxt::TextureFormat format) {
switch (format) {
case nxt::TextureFormat::R8G8B8A8Unorm:
return DXGI_FORMAT_R8G8B8A8_UNORM;
default:
UNREACHABLE();
}
}
}
Texture::Texture(Device* device, TextureBuilder* builder)
: TextureBase(builder), device(device) {
D3D12_RESOURCE_DESC resourceDescriptor;
resourceDescriptor.Dimension = D3D12TextureDimension(GetDimension());
resourceDescriptor.Alignment = 0;
resourceDescriptor.Width = GetWidth();
resourceDescriptor.Height = GetHeight();
resourceDescriptor.DepthOrArraySize = static_cast<UINT16>(GetDepth());
resourceDescriptor.MipLevels = static_cast<UINT16>(GetNumMipLevels());
resourceDescriptor.Format = D3D12TextureFormat(GetFormat());
resourceDescriptor.SampleDesc.Count = 1;
resourceDescriptor.SampleDesc.Quality = 0;
resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
resourceDescriptor.Flags = D3D12ResourceFlags(GetUsage(), GetFormat());
resource = device->GetResourceAllocator()->Allocate(D3D12_HEAP_TYPE_DEFAULT, resourceDescriptor, D3D12TextureUsage(GetUsage(), GetFormat()));
}
Texture::~Texture() {
device->GetResourceAllocator()->Release(resource);
}
DXGI_FORMAT Texture::GetD3D12Format() const {
return D3D12TextureFormat(GetFormat());
}
ComPtr<ID3D12Resource> Texture::GetD3D12Resource() {
return resource;
}
bool Texture::GetResourceTransitionBarrier(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier) {
D3D12_RESOURCE_STATES stateBefore = D3D12TextureUsage(currentUsage, GetFormat());
D3D12_RESOURCE_STATES stateAfter = D3D12TextureUsage(targetUsage, GetFormat());
if (stateBefore == stateAfter) {
return false;
}
barrier->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier->Transition.pResource = resource.Get();
barrier->Transition.StateBefore = stateBefore;
barrier->Transition.StateAfter = stateAfter;
barrier->Transition.Subresource = 0;
return true;
}
void Texture::TransitionUsageImpl(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage) {
D3D12_RESOURCE_BARRIER barrier;
if (GetResourceTransitionBarrier(currentUsage, targetUsage, &barrier)) {
device->GetPendingCommandList()->ResourceBarrier(1, &barrier);
}
}
TextureView::TextureView(TextureViewBuilder* builder)
: TextureViewBase(builder) {
srvDesc.Format = D3D12TextureFormat(GetTexture()->GetFormat());
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
switch (GetTexture()->GetDimension()) {
case nxt::TextureDimension::e2D:
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = GetTexture()->GetNumMipLevels();
srvDesc.Texture2D.PlaneSlice = 0;
srvDesc.Texture2D.ResourceMinLODClamp = 0;
break;
}
}
const D3D12_SHADER_RESOURCE_VIEW_DESC& TextureView::GetSRVDescriptor() const {
return srvDesc;
}
}
}