Overview
- Obtain a session as in earlier tutorials (rejoin or onboard)
- Create the app volume the stream is displayed in
- Wait for a peer (e.g. a Visualizer) to request a render stream
- Create a D3D11 device, chain it into the render sender with QarStreamParamsD3D11, and clear each colour view of the sender's shared textures directly on the GPU - no CPU copy
Prerequisites
- Complete the CPU Rendering with a Visualizer tutorial; this one differs only in the graphics backend
- Windows with a D3D11.1-capable GPU
- A running QarOS hub (for the first run, read the pairing code off its onboarding screen), with a peer that requests a render stream from this application once it is running
Build and Run
cmake --build --preset x64-windows-debug --target d3d11_render_sender
./build/x64-windows/Debug/d3d11_render_sender.exe
<path-to-qar-streaming-c.dll> [runtime-dir] [pairing-code]
Library, Runtime, Session, and App Volume
Argument parsing and session setup match the CPU Rendering with a Visualizer tutorial. A render sender is displayed in an app volume, so one is created before the sender.
volume_init.common_name = "d3d11-volume.examples.qaros";
log_result("qar_app_volumes_get_or_create", volume_result);
{
return 6;
}
Create the D3D11 Device
The sender needs the ID3D11Device1 / ID3D11DeviceContext1 interfaces, so the device is created as usual and queried for them.
static bool
{
const D3D_FEATURE_LEVEL levels[] = { D3D_FEATURE_LEVEL_11_1 };
ID3D11Device* device = NULL;
ID3D11DeviceContext* context = NULL;
HRESULT hr = D3D11CreateDevice(
NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
levels,
1,
D3D11_SDK_VERSION,
&device,
NULL,
&context
);
if(FAILED(hr))
{
fprintf(stderr, "D3D11CreateDevice failed (0x%08lX)\n", (unsigned long)hr);
return false;
}
HRESULT device_hr =
ID3D11Device_QueryInterface(device, &IID_ID3D11Device1, (void**)&out_d3d->device);
HRESULT context_hr = ID3D11DeviceContext_QueryInterface(
context, &IID_ID3D11DeviceContext1, (void**)&out_d3d->context
);
ID3D11DeviceContext_Release(context);
ID3D11Device_Release(device);
if(FAILED(device_hr) || FAILED(context_hr))
{
fprintf(stderr, "D3D11.1 interfaces not available\n");
return false;
}
return true;
}
Create the D3D11 Render Sender
Select QAR_GRAPHICS_API_D3D11 and chain QarStreamParamsD3D11 into QarRenderSenderInit::header.next. The bind flags decide how the shared textures can be used; keep acquire_keyed_mutex_sync true so the library acquires and releases each texture's keyed mutex around the frame cycle.
d3d11_params.color_bind_flags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
d3d11_params.depth_bind_flags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
sender_init.peer_id = request_state.target_peer_id;
log_result("qar_render_sender_create", sender_result);
{
return 9;
}
Render and Submit Frames
Inside each begin-frame / show-frame cycle, qar_render_sender_frame_d3d11() hands out the shared textures and the views laid out on them. Each colour view is a pixel rectangle on one texture; here it is cleared to an animated colour with ID3D11DeviceContext1::ClearView. A real renderer draws its scene into the same rectangle, using the view poses from the frame info.
const size_t frame_count = 300;
for(size_t frame_index = 0; frame_index < frame_count; ++frame_index)
{
{
log_result("qar_render_sender_begin_frame", begin_result);
break;
}
{
}
else
{
log_result("qar_render_sender_frame_d3d11", frame_result);
}
{
log_result("qar_render_sender_show_frame", show_result);
break;
}
}
The clear itself:
static void
ID3D11Device1* device,
ID3D11DeviceContext1* context,
size_t frame_index
)
{
const float t = (float)(frame_index % 120) / 120.0f;
{
{
continue;
}
ID3D11RenderTargetView* rtv = NULL;
HRESULT hr =
ID3D11Device1_CreateRenderTargetView(device, (ID3D11Resource*)texture, NULL, &rtv);
if(FAILED(hr))
{
fprintf(stderr, "CreateRenderTargetView failed (0x%08lX)\n", (unsigned long)hr);
continue;
}
const float color[4] = { right ? 0.1f : t, 0.2f, right ? t : 0.1f, 1.f };
const D3D11_RECT rect = {
};
ID3D11DeviceContext1_ClearView(context, (ID3D11View*)rtv, color, &rect, 1);
ID3D11RenderTargetView_Release(rtv);
}
}
Generated via doxygen2docusaurus 2.2.1 by Doxygen 1.9.8.