Direct3D | HackLAB https://www.geeks3d.com/hacklab 3D Programming, Prototyping and Gamedev with GeeXLab Sat, 11 Nov 2017 12:58:09 +0000 en-US hourly 1 https://wordpress.org/?v=6.7.1 How to Run a Vulkan or Direct3D 12 Demo on a Particular GPU https://www.geeks3d.com/hacklab/20160511/how-to-run-a-vulkan-or-direct3d-12-demo-on-a-particular-gpu/ https://www.geeks3d.com/hacklab/20160511/how-to-run-a-vulkan-or-direct3d-12-demo-on-a-particular-gpu/#respond Wed, 11 May 2016 19:19:23 +0000 http://www.geeks3d.com/hacklab/?p=1103 Both Vulkan and Direct3D 12, the new low level graphics APIs, offer a nice feature so far reserved to computing APIs (OpenCL or CUDA): the ability to run graphics tasks on a particular GPU. If you have more than one GPU in your system (for example two or three single GPU graphics cards, or one dual-GPU card like a Radeon R9 295X or a GeForce … Continue reading How to Run a Vulkan or Direct3D 12 Demo on a Particular GPU »

The post How to Run a Vulkan or Direct3D 12 Demo on a Particular GPU first appeared on HackLAB.]]>


Both Vulkan and Direct3D 12, the new low level graphics APIs, offer a nice feature so far reserved to computing APIs (OpenCL or CUDA): the ability to run graphics tasks on a particular GPU.

If you have more than one GPU in your system (for example two or three single GPU graphics cards, or one dual-GPU card like a Radeon R9 295X or a GeForce GTX Titan Z), you can select a specific GPU and run a Vulkan or Direct3D 12 demo on this GPU.

With OpenGL, this is not possible on Windows. OpenGL has one renderer (usually the first GPU) and the only way to use the second GPU is to enable SLI or CrossFire. But even with SLI / CrossFire, OpenGL sees only one renderer which is a logical GPU. On a system with one physical GPU, OpenGL sees one logical GPU made up of one physical GPU and on a system with two GPUs (and with SLI or CrossFire enabled), OpenGL still sees one logical GPU made up of two physical GPUs.

As a programmer, you can not assign graphics / compute task to a particular GPU in OpenGL on Windows. This limitation has been removed by Vulkan and Direct3D 12.

On Linux and OS X, you run an OpenGL demo on a particular GPU. On Linux you have to create a context on the proper display, while virtual screens do the job on OS X.

You can easily test this feature with the latest GeeXLab. Just take any Vulkan demo of the code sample pack (in the vk/ folder), and change the value of the gpu_index attribute of the window XML node. The following code snippet show how to run the demo on the first GPU (index = 0):

  

 
To run the demo on the second GPU (index = 1):

  

 
GeeXLab allows to create several 3D windows in the same demo (each window running its own set of scripts: INIT, FRAME, etc.). I prepared a Vulkan demo that creates two 3D windows, each window being assigned to a particular GPU. On my dev system, I have two cards: GeForce GTX 960 + GeForce GTX 750. The first window will run on the GTX 960 and the second will run on the GTX 750:

  
          
  
  

 
The demo is available here: vk/02-triangle-of-death-multiple-windows.xml


Vulkan multi-GPU demo

 
Remark: at the time of writing, the multiple windows feature works only on Windows. There is a bug that prevent to run it on Linux. I hope to fix it for the next release…

The post How to Run a Vulkan or Direct3D 12 Demo on a Particular GPU first appeared on HackLAB.]]>
https://www.geeks3d.com/hacklab/20160511/how-to-run-a-vulkan-or-direct3d-12-demo-on-a-particular-gpu/feed/ 0
Introduction to Direct3D 12 Programming with GeeXLab https://www.geeks3d.com/hacklab/20160105/introduction-to-direct3d-12-programming-with-geexlab/ https://www.geeks3d.com/hacklab/20160105/introduction-to-direct3d-12-programming-with-geexlab/#respond Tue, 05 Jan 2016 16:22:26 +0000 http://www.geeks3d.com/hacklab/?p=866 Since GeeXLab version 0.9+, a Direct3D 12 renderer plugin is available in the Windows versions (32 and 64-bit). A complete and efficient implementation of a Direct3D 12 based renderer is a big and tough task. The current D3D12 plugin shipped with GeeXLab does not provide a full support (for example the management of several GPUs is not yet implemented in the plugin) but most of … Continue reading Introduction to Direct3D 12 Programming with GeeXLab »

The post Introduction to Direct3D 12 Programming with GeeXLab first appeared on HackLAB.]]>
Since GeeXLab version 0.9+, a Direct3D 12 renderer plugin is available in the Windows versions (32 and 64-bit).

A complete and efficient implementation of a Direct3D 12 based renderer is a big and tough task. The current D3D12 plugin shipped with GeeXLab does not provide a full support (for example the management of several GPUs is not yet implemented in the plugin) but most of the basic functionalities is available: command lists (CL), pipeline state objects (PSO), constant buffers (CB) and HLSL shaders.

In this introduction, we’re going to see how to draw the hello world of graphics programming: a simple RGB triangle.


GeeXLab - Direct3D 12 demo - RGB Triangle

The full GeeXLab demo (02-triangle-of-death.xml) is available in the host_api/Direct3D12/ folder of the code sample pack.

 
This example is simple but at the same time, CL, PSO and HLSL shaders are all utilized.

The principle of Direct3D 12 is quite simple: the render calls are stored in a command list. Once all render call are stored, the command list is executed.

The first thing to do is to tell GeeXLab that the demo will use a D3D12 renderer instead of the default OpenGL renderer. This is done in the XML window node with the renderer_type attribute:

  <window name="win3d01" title="Direct3D 12 demo" 
          width="800" height="400" 
          renderer_type="Direct3D12" />

 
Now we can script (currently, the functions required by D3D12 are only available in Lua, I will update the Python plugin later). Let’s see the content of the INIT script.

The first step is to create a command list and open it:

cl = gh_renderer.command_list_create()
gh_renderer.command_list_open(cl)

 
Now all usual GeeXLab functions will fill the command list. For example, the initialization of the mesh triangle will fill the current command list in an implicit way:

triangle = gh_mesh.create_v2()
local num_vertices = 3
local num_faces = 0 -- non-indexed rendering
local ret = gh_mesh.alloc_mesh_data(triangle, num_vertices, num_faces)
if (ret == 1) then
  gh_mesh.set_vertex_position(triangle, 0, -2, -2, 0, 1)
  gh_mesh.set_vertex_position(triangle, 1, 0, 2, 0, 1)
  gh_mesh.set_vertex_position(triangle, 2, 2, -2, 0, 1)

  gh_mesh.set_vertex_color(triangle, 0, 1, 0, 0, 1) -- red
  gh_mesh.set_vertex_color(triangle, 1, 0, 1, 0, 1) -- green
  gh_mesh.set_vertex_color(triangle, 2, 0, 0, 1, 1) -- blue
end 

 
Direct3D 12 introduced a new object in order to optimize rendering: the Pipeline State Object or PSO. In short, a PSO describes a whole GPU context required for a particular type of rendering. The depth state, blending state, fill mode (solid, wireframe) are few states included in a PSO. A PSO includes a GPU program as well. A PSO is an immutable object: once built, it can not be updated… You follow me? Yes, your big D3D12 demo will have a lot of PSOs…

The creation and initialization of a PSO suited for our needs can be done with:

local RENDERER_POLYGON_MODE_POINT = 0
local RENDERER_POLYGON_MODE_LINE = 1
local RENDERER_POLYGON_MODE_SOLID = 2
local PRIMITIVE_TRIANGLE = 0
local PRIMITIVE_LINE = 2
local PRIMITIVE_POINT = 8

pso01 = gh_renderer.pipeline_state_create("pso01", vertex_color_prog, "")
gh_renderer.pipeline_state_set_attrib_4i(pso01, "DEPTH_TEST", 1, 0, 0, 0)
gh_renderer.pipeline_state_set_attrib_4i(pso01, "FILL_MODE", RENDERER_POLYGON_MODE_SOLID, 0, 0, 0)
gh_renderer.pipeline_state_set_attrib_4i(pso01, "PRIMITIVE_TYPE", PRIMITIVE_TRIANGLE, 0, 0, 0)
local ret = gh_renderer.pipeline_state_build(pso01)
if (ret == 0) then
	print("ERROR: pipeline state pso01 is not valid.")
end

 
Once the scene objects have been all initialized, we can close and perform a first execution of the command list in order to really create all GPU objects:

gh_renderer.command_list_close(cl)
gh_renderer.command_list_execute(cl)
gh_renderer.wait_for_gpu()

 
gh_renderer.wait_for_gpu() allows to synchronize the GPU and CPU operations.

Now we can detail the content of a FRAME script that will render our nice RGB triangle:

-- Reset the command list
gh_renderer.command_list_frame_begin(cl)

-- The draw calls will be rendered in the default framebuffer.
gh_renderer.d3d12_bind_framebuffer(cl)

-- Bind the camera and clear the color buffer.
gh_camera.bind(camera)
gh_renderer.clear_color_depth_buffers(0.2, 0.2, 0.2, 1.0, 1.0)

-- Bind the PSO
gh_renderer.pipeline_state_bind(pso01)

-- Render the triangle
gh_object.render(triangle)

-- Close the command list and execute it.
gh_renderer.command_list_frame_end(cl)

As I said, all render states and GPU program (in HLSL) are embedded in a PSO. So to render the triangle, we just need to bind the PSO and draw the triangle:

gh_renderer.pipeline_state_bind(pso01)
gh_object.render(triangle)

 
To end up the article, here is the HLSL program used to draw the triangle:

// ModelViewTransforms constant buffer uses b0 shader register in space register 1 
// (defined in GeeXLab).
//
cbuffer ModelViewTransforms : register(b0,space1) 

{
  column_major float4x4 ModelViewProjectionMatrix : packoffset(c0); 
  column_major float4x4 ModelViewMatrix : packoffset(c4);
  column_major float4x4 ModelMatrix : packoffset(c8);
  column_major float4x4 ViewMatrix : packoffset(c12);
  column_major float4x4 ProjectionMatrix : packoffset(c16);
  column_major float4x4 ViewProjectionMatrix : packoffset(c20);
  //float4 Viewport : packoffset(c24);
};

struct VSInput
{
  float4  Position : POSITION;
  float4  TexCoord : TEXCOORD;
  float4  Normal   : NORMAL;
  float4  Color    : COLOR;
};

struct PSInput
{
  float4 position : SV_POSITION;
  float4 color : COLOR;
};

PSInput VSMain(VSInput input)
{
  PSInput result;
  result.position = mul(ModelViewProjectionMatrix, float4(input.Position.xyz, 1.0)); 
  result.color = input.Color;
  return result;
}

float4 PSMain(PSInput input) : SV_TARGET
{
  return input.color;
}

 
All transformation matrices are passed to the program via a constant buffer called ModelViewTransforms. This particular constant buffer is managed by GeeXLab so no need to worry about it. All you need to know is that this constant buffer is bound to the register b0 of the shader register space 1: register(b0,space1). This is important otherwise your HLSL program won’t be compiled.

More Direct3D 12 demos are available in the host_api/Direct3D12 folder of the code sample pack. Do not hesitate to hack them in order to understand how they work. And if you are stuck on a problem, the forum is there (EN) or there (FR).

The post Introduction to Direct3D 12 Programming with GeeXLab first appeared on HackLAB.]]>
https://www.geeks3d.com/hacklab/20160105/introduction-to-direct3d-12-programming-with-geexlab/feed/ 0