4.12 Is there a much simpler way to upload a texture in Direct3D12?
We have written the following two experimental classes:
1. ImageFileReader to read a JPG or PNG image file using
JPGFileReader and
PNGFileReader,
and get the pixel data in order
to create an intermediate texture resource.
2. Direct3D12IntermediateResource to upload an intermediate texture resource to a target texture resource.
You can easily see these classes are much simpler than classes WICBitmapFileReader and
Direct3D12Subresources.
Object
ImageFileReader
ComIUnknown
Direct3D12Object
Direct3D12DeviceChild
Direct3D12Pageable
Direct3D12Resource
Direct3D12IntermediateResource
The following Direct3D12PNGTexturedCubeByIntermediateResourceAndImageFileReader is a very simple sample program to render a PNG textured cube.
You can see this source code is almost the same as that of 4.11 Direct3D12BMPPNGTexturedCube program.
/*
* Direct3D12PNGTexturedCubeByIntermediateResourceAndImageFileReader.cpp
* Copyright (c) 2016 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED.
*/
// 2016/11/21
// This is a simpe program to use ImageFileReader which is a JPG/PNG image file reader,
// and Direct3D12IntermediateResource which is an intermediate texture resource uploader
// to a destintation texture resource.
//
#define COMMONCONTROLS_V6
#define WIN10
#include <sol/COMInitializer.h>
#include <sol/CharModuleFileName.h>
#include <sol/direct3d12/DirectX3D12MainView.h>
#include <sol/direct3d12/DirectX3D12View.h>
#include <sol/direct3d12/DirectXMatrix.h>
#include <sol/direct3d12/Direct3D12CommandAllocator.h>
#include <sol/direct3d12/Direct3D12RenderTargetView.h>
#include <sol/direct3d12/Direct3D12DepthStencilView.h>
#include <sol/direct3d12/Direct3D12CommonDescriptorHeap.h>
#include <sol/direct3d12/Direct3D12TransformConstantBufferView.h>
#include <sol/direct3d12/Direct3D12TextureRootSignature.h>
#include <sol/direct3d12/Direct3D12GraphicsCommandList.h>
#include <sol/direct3d12/Direct3D12Fence.h>
#include <sol/direct3d12/Direct3D12PipelineState.h>
#include <sol/direct3d12/D3D12RasterizerDesc.h>
#include <sol/direct3d12/D3D12BlendDesc.h>
#include <sol/direct3d12/D3D12GraphicsPipelineStateDesc.h>
#include <sol/direct3d12/D3D12ResourceBarrier.h>
#include <sol/direct3d12/D3D12Transform.h>
#include <sol/direct3d12/Direct3D12GraphicsCommandList.h>
#include <sol/direct3d12/Direct3D12Synchronizer.h>
#include <sol/direct3d12/Direct3D12Texture2D.h>
#include <sol/direct3d12/Direct3DX12TexturedCube.h>
#include <sol/direct3d12/Direct3D12ShaderResourceView.h>
#include <sol/direct3d12/Direct3D12Sampler.h>
#include <sol/direct3d12/Direct3DX12ColoredCube.h>
#include <sol/direct3d12/DirectXTransform.h>
#include <sol/direct3d12/Direct3D12IntermediateResource.h>
#include <sol/ImageFileReader.h>
#include <sol/direct3d12/D3D12SubresourceData.h>
#include "resource.h"
namespace SOL {
class MainView :public DirectX3D12MainView {
//Inner class
class SimpleView :public DirectX3D12View {
private:
SmartPtr<Direct3D12CommandAllocator> commandAllocator;
SmartPtr<Direct3D12RenderTargetView> renderTargetView;
SmartPtr<Direct3D12DepthStencilView> depthStencilView;
SmartPtr<Direct3D12TextureRootSignature> rootSignature;
SmartPtr<Direct3D12CommonDescriptorHeap> commonDescriptorHeap;
SmartPtr<Direct3D12TransformConstantBufferView> constantBufferView;
SmartPtr<Direct3D12ShaderResourceView> shaderResourceView;
SmartPtr<Direct3D12GraphicsCommandList> graphicsCommandList;
SmartPtr<Direct3D12PipelineState> pipelineState;
SmartPtr<Direct3D12Synchronizer> synchronizer;
SmartPtr<Direct3DX12TexturedCube> texturedCube;
SmartPtr<Direct3D12IntermediateResource> intermediateResource;
SmartPtr<Direct3D12Texture2D> texture2D;
UINT frameIndex;
DirectXTransform worldViewProjection;
float angle;
StringT<TCHAR> directory;
private:
virtual void createPipelineState(ID3D12Device* device)
{
//Create a graphicPipelineStateDes.
D3D12GraphicsPipelineStateDesc graphicsPipelineStateDesc(*rootSignature);
UINT count = 0;
const D3D12_INPUT_ELEMENT_DESC* inputElements = texturedCube->getInputElementDesc(count);
D3D12RasterizerDesc rasterDesc(
D3D12_FILL_MODE_SOLID,
D3D12_CULL_MODE_NONE,
false);
D3D12BlendDesc blendDesc;
graphicsPipelineStateDesc.setInputLayput(inputElements, count);
graphicsPipelineStateDesc.setRasterizerState(rasterDesc);
graphicsPipelineStateDesc.setBlendState(blendDesc);
StringT<TCHAR> vsshaderFile = getShaderFilePath(directory, _T("VertexShader.cso"));
StringT<TCHAR> psshaderFile = getShaderFilePath(directory, _T("PixelShader.cso"));
graphicsPipelineStateDesc.setVertexShader(vsshaderFile);
graphicsPipelineStateDesc.setPixelShader(psshaderFile);
pipelineState = new Direct3D12PipelineState(device, graphicsPipelineStateDesc);
}
void setDirectXTransform()
{
int width = 0;
int height = 0;
getClientSize(width, height);
try {
XMVECTOR eye = XMVectorSet( 1.0f, 2.0f, 5.0f, 0.0f );
XMVECTOR at = XMVectorSet( 0.0f, 0.0f, 0.0f, 0.0f );
XMVECTOR up = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );
worldViewProjection.world = DirectXMatrix::rotationY( angle );
worldViewProjection.view = DirectXMatrix::lookAtLH(eye, at, up);
worldViewProjection.projection = DirectXMatrix::perspectiveFovLH( XM_PIDIV2*0.4f, width / (FLOAT)height, 0.01f, 100.0f );
if (constantBufferView) {
constantBufferView->update(worldViewProjection);
}
} catch (Exception& ex) {
caught(ex);
}
}
//Create a renderTargetView and a depthStencilView.
void createViews(ID3D12Device* device, IDXGISwapChain3* swapChain,
int width, int height)
{
renderTargetView = new Direct3D12RenderTargetView(device, swapChain);
depthStencilView = new Direct3D12DepthStencilView(device, width, height);
}
//Delete a renderTargetView and a depthStencilView.
void deleteViews()
{
if (graphicsCommandList == nullptr) {
throw IException("graphicsCommandList is NULL.")
}
graphicsCommandList->setOMRenderTargets(0, nullptr, FALSE, nullptr);
renderTargetView = NULL;
depthStencilView = NULL;
}
//Read a jpg or png image by using ImageFileReader.
void readImageFile(__out int& width, __out int& height, __out D3D12SubresourceData& subresource)
{
CharModuleFileName moduleFileName;
const char* dir = moduleFileName.getDir();
char path[MAX_PATH];
sprintf_s(path, CountOf(path), "%s\\..\\image\\%s", dir, "flower.png");
ImageInfo imageInfo;
ImageFileReader reader(path, imageInfo);
width = imageInfo.width;
height = imageInfo.height;
subresource.set(imageInfo.width,
imageInfo.height,
imageInfo.rowBytes,
imageInfo.imageDataSize,
imageInfo.imageData,
imageInfo.format);
}
public:
virtual void initialize()
{
int width = 0;
int height = 0;
validateClientSize(width, height);
Direct3D12Device* device = getD3D12Device();
DirectXGISwapChain3* swapChain = getSwapChain3();
Direct3D12CommandQueue* commandQueue = getCommandQueue();
try {
commandAllocator = new Direct3D12CommandAllocator(*device);
graphicsCommandList = new Direct3D12GraphicsCommandList(*device, *commandAllocator);
rootSignature = new Direct3D12TextureRootSignature(*device);
synchronizer = new Direct3D12Synchronizer(*device, *commandQueue);
createViews(*device, *swapChain, width, height);
texturedCube = new Direct3DX12TexturedCube(*device, 1.0f);
D3D12SubresourceData imageResource;
//Get texture width, height and texture imageResource
int twidth = 0;
int theight = 0;
readImageFile(twidth, theight, imageResource);
//Create a textured of size specified twidth and theight;
texture2D = new Direct3D12Texture2D(*device,
twidth,
theight, imageResource.getFormat());
//Create an intermediate texture resource from the texture2D and the imageResource.
intermediateResource = new Direct3D12IntermediateResource(*device, *texture2D, imageResource);
commonDescriptorHeap = new Direct3D12CommonDescriptorHeap(*device);
constantBufferView = new Direct3D12TransformConstantBufferView(*device,
commonDescriptorHeap->getCPUHandle(CBV_HANDLE));
//Update the intermediate texture resource to the destionation texture2D.
intermediateResource -> upload(*graphicsCommandList,
*commandAllocator,
*commandQueue,
synchronizer);
shaderResourceView = new Direct3D12ShaderResourceView(*device,
commonDescriptorHeap->getCPUHandle(SRV_HANDLE),
*texture2D);
createPipelineState(*device);
setDirectXTransform();
} catch (Exception& ex) {
caught(ex);
}
}
bool ready()
{
Direct3D12Device* device = getD3D12Device();
DirectXGISwapChain3* swapChain = getSwapChain3();
Direct3D12CommandQueue* commandQueue = getCommandQueue();
if (
device == nullptr ||
commandQueue == nullptr ||
swapChain == nullptr ||
commandAllocator == nullptr ||
renderTargetView == nullptr ||
depthStencilView == nullptr ||
rootSignature == nullptr ||
constantBufferView == nullptr ||
texturedCube == nullptr ||
texture2D == nullptr ||
intermediateResource == nullptr ||
shaderResourceView == nullptr ||
graphicsCommandList == nullptr ||
pipelineState == nullptr ||
synchronizer == nullptr ) {
return false;
}
return true;
}
virtual void display()
{
int width = 0;
int height = 0;
validateClientSize(width, height);
if ( !ready() ) {
return;
}
try {
Direct3D12Device* device = getD3D12Device();
DirectXGISwapChain3* swapChain = getSwapChain3();
Direct3D12CommandQueue* commandQueue = getCommandQueue();
worldViewProjection.world = DirectXMatrix::rotationY( angle );
constantBufferView->update(worldViewProjection);
commandAllocator -> reset();
graphicsCommandList->reset(*commandAllocator, nullptr);
frameIndex = swapChain -> getCurrentBackBufferIndex();
D3D12ResourceBarrier barrier(renderTargetView->getResource(frameIndex));
barrier.startRendering();
graphicsCommandList->resourceBarrier(1, barrier);
graphicsCommandList->setDescriptorHeap(*commonDescriptorHeap);
graphicsCommandList->setGraphicsRootSignature(*rootSignature);
graphicsCommandList->setPipelineState(*pipelineState);
graphicsCommandList->setGraphicsRootDescriptorTable(CBV_HANDLE,
commonDescriptorHeap->getGPUHandle(CBV_HANDLE)); //ConstantBufferView
graphicsCommandList->setGraphicsRootDescriptorTable(SRV_HANDLE,
commonDescriptorHeap->getGPUHandle(SRV_HANDLE)); //ShaderResourceView
graphicsCommandList -> setRSViewport(width, height);
graphicsCommandList -> setRSScissorRect(width, height);
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = renderTargetView->getHandle(frameIndex);
graphicsCommandList->clearRenderTargetView(rtvHandle, XMColor(0.0f, 0.0f, 0.0f, 1.0f));
D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = *depthStencilView;
graphicsCommandList->clearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH);
graphicsCommandList->setOMRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
texturedCube -> drawIndexedInstanced(graphicsCommandList);
barrier.endRendering();
graphicsCommandList->resourceBarrier(1, barrier);
graphicsCommandList->close();
commandQueue->executeCommandList(*graphicsCommandList);
swapChain->present(1, 0);
synchronizer->waitForCompletion();
} catch (Exception& ex) {
caught(ex);
}
}
virtual void resize(int width, int height)
{
Direct3D12Device* device = getD3D12Device();
DirectXGISwapChain3* swapChain = getSwapChain3();
if (device == NULL ||
swapChain == NULL) {
return ;
}
try {
deleteViews();
swapChain->resizeBuffers(width, height);
createViews(*device, *swapChain, width, height);
} catch (Exception& ex) {
caught(ex);
}
}
void render()
{
angle += 0.02f;
display();
}
void incrementAngle()
{
angle += 0.1f;
display();
}
void decrementAngle()
{
angle -= 0.1f;
display();
}
public:
//Constructor
SimpleView(DirectX3D12MainView* parent, const TCHAR* name, Args& args)
:DirectX3D12View(parent, name, args),
angle (0.6f),
frameIndex(0),
directory(_T(""))
{
directory = (const TCHAR*)args.get(XmNapplicationDirectory);
postResizeRequest();
}
~SimpleView()
{
}
};
// Inner class ends.
private:
SmartPtr<SimpleView> view;
public:
/**
* Constructor
*/
MainView(Application& applet, const TCHAR* name, Args& args)
:DirectX3D12MainView(applet, name,
args.set(XmNstyle, (ulong)WS_CLIPCHILDREN|WS_CLIPSIBLINGS) )
{
const TCHAR* directory = (const TCHAR*)args.get(XmNapplicationDirectory);
// 1 Restore the replacement of MainView
restorePlacement();
// 2 Create a view of SimpleView.
Args ar;
int width = 0;
int height = 0;
getClientSize(width, height);
ar.set(XmNwidth, width);
ar.set(XmNheight,height);
ar.set(XmNapplicationDirectory, (const TCHAR*)directory);
view = new SimpleView(this, _T(""), ar);
// 3 Post a resize request to this MainView.
postResizeRequest();
}
public:
~MainView()
{
}
void resize(int width, int height)
{
if (view != nullptr) {
view -> reshape(0, 0, width, height);
}
}
virtual void keyDown(Event& event)
{
WPARAM wparam = event.getWParam();
switch(wparam) {
case VK_LEFT:
view -> decrementAngle();
break;
case VK_RIGHT:
view -> incrementAngle();
break;
}
}
};
}
//////////////////////////////////////////////
//
void Main(int argc, TCHAR** argv)
{
TCHAR directory[MAX_PATH];
appDirectory(argv[0], directory, CountOf(directory));
const TCHAR* appClass = appName(argv[0]);
try {
//For DXGI components.
COMInitializer initializer( COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
Application applet(appClass, argc, argv);
Args args;
args.set(XmNwidth, 480);
args.set(XmNheight, 480);
args.set(XmNapplicationDirectory, directory);
MainView mainView(applet, appClass, args);
mainView.realize();
applet.run();
} catch (Exception& ex) {
caught(ex);
}
}
Last modified: 24 Nov 2016
Copyright (c) 2016 Antillia.com ALL RIGHTS RESERVED.