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.