diff --git a/CMakeLists.txt b/CMakeLists.txt index d3fcec13bd012f..c8fbd7cebc9846 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ add_subdirectory(libobs) if(OS_WINDOWS) add_subdirectory(libobs-d3d11) add_subdirectory(libobs-winrt) + add_subdirectory(libobs-d3d12) endif() add_subdirectory(libobs-opengl) add_subdirectory(plugins) diff --git a/libobs-d3d12/CMakeLists.txt b/libobs-d3d12/CMakeLists.txt new file mode 100644 index 00000000000000..e9e6bdf4bb2be3 --- /dev/null +++ b/libobs-d3d12/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.24...3.29) + +add_library(libobs-d3d12 MODULE) +add_library(OBS::libobs-d3d12 ALIAS libobs-d3d12) + +target_sources(libobs-d3d12 PRIVATE d3d12-subsystem.cpp d3d12-subsystem.hpp) + +configure_file(cmake/windows/obs-module.rc.in libobs-d3d12.rc) +target_sources(libobs-d3d12 PRIVATE libobs-d3d12.rc) + +target_compile_definitions( + libobs-d3d12 + PRIVATE + $<$:USE_GPU_PRIORITY> + "$,GPU_PRIORITY_VAL=${GPU_PRIORITY_VAL},GPU_PRIORITY_VAL=0>" +) + +target_link_libraries(libobs-d3d12 PRIVATE OBS::libobs d3d12 dxgi) + +set_target_properties_obs( + libobs-d3d12 + PROPERTIES FOLDER core + VERSION 0 + SOVERSION ${OBS_VERSION_MAJOR} + COMPILE_WARNING_AS_ERROR FALSE +) diff --git a/libobs-d3d12/cmake/windows/obs-module.rc.in b/libobs-d3d12/cmake/windows/obs-module.rc.in new file mode 100644 index 00000000000000..0ebf14e51f19cb --- /dev/null +++ b/libobs-d3d12/cmake/windows/obs-module.rc.in @@ -0,0 +1,24 @@ +1 VERSIONINFO +FILEVERSION ${OBS_VERSION_MAJOR},${OBS_VERSION_MINOR},${OBS_VERSION_PATCH},0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "${OBS_COMPANY_NAME}" + VALUE "FileDescription", "OBS Library D3D11 wrapper" + VALUE "FileVersion", "${OBS_VERSION_CANONICAL}" + VALUE "ProductName", "${OBS_PRODUCT_NAME}" + VALUE "ProductVersion", "${OBS_VERSION_CANONICAL}" + VALUE "Comments", "${OBS_COMMENTS}" + VALUE "LegalCopyright", "${OBS_LEGAL_COPYRIGHT}" + VALUE "InternalName", "libobs-d3d12" + VALUE "OriginalFilename", "libobs-d3d12" + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 0x04B0 + END +END diff --git a/libobs-d3d12/d3d12-subsystem.cpp b/libobs-d3d12/d3d12-subsystem.cpp new file mode 100644 index 00000000000000..04ff1a5314e9fd --- /dev/null +++ b/libobs-d3d12/d3d12-subsystem.cpp @@ -0,0 +1,1195 @@ +/****************************************************************************** + Copyright (C) 2023 by Lain Bailey + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "d3d12-subsystem.hpp" +#include + +struct UnsupportedHWError : HRError { + inline UnsupportedHWError(const char *str, HRESULT hr) + : HRError(str, hr) + { + } +}; + +#ifdef _MSC_VER +/* alignment warning - despite the fact that alignment is already fixed */ +#pragma warning(disable : 4316) +#endif + +static inline void LogD3D12ErrorDetails(HRError error, gs_device_t *device) +{ + if (error.hr == DXGI_ERROR_DEVICE_REMOVED) { + HRESULT DeviceRemovedReason = + device->device->GetDeviceRemovedReason(); + blog(LOG_ERROR, " Device Removed Reason: %08lX", + DeviceRemovedReason); + } +} + +gs_obj::gs_obj(gs_device_t *device_, gs_type type) + : device(device_), + obj_type(type) +{ + prev_next = &device->first_obj; + next = device->first_obj; + device->first_obj = this; + if (next) + next->prev_next = &next; +} + +gs_obj::~gs_obj() +{ + if (prev_next) + *prev_next = next; + if (next) + next->prev_next = prev_next; +} + +static enum gs_color_space get_next_space(gs_device_t *device, HWND hwnd, + DXGI_SWAP_EFFECT effect) +{ + enum gs_color_space next_space = GS_CS_SRGB; + if (effect == DXGI_SWAP_EFFECT_FLIP_DISCARD) { + const HMONITOR hMonitor = + MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); + if (hMonitor) { + const gs_monitor_color_info info = + device->GetMonitorColorInfo(hMonitor); + if (info.hdr) + next_space = GS_CS_709_SCRGB; + else if (info.bits_per_color > 8) + next_space = GS_CS_SRGB_16F; + } + } + + return next_space; +} + +static enum gs_color_format +get_swap_format_from_space(gs_color_space space, gs_color_format sdr_format) +{ + gs_color_format format = sdr_format; + switch (space) { + case GS_CS_SRGB_16F: + case GS_CS_709_SCRGB: + format = GS_RGBA16F; + } + + return format; +} + +static inline enum gs_color_space +make_swap_desc(gs_device *device, DXGI_SWAP_CHAIN_DESC &desc, + const gs_init_data *data, DXGI_SWAP_EFFECT effect, UINT flags) +{ + const HWND hwnd = (HWND)data->window.hwnd; + const enum gs_color_space space = get_next_space(device, hwnd, effect); + const gs_color_format format = + get_swap_format_from_space(space, data->format); + + memset(&desc, 0, sizeof(desc)); + desc.BufferDesc.Width = data->cx; + desc.BufferDesc.Height = data->cy; + desc.BufferDesc.Format = ConvertGSTextureFormatView(format); + desc.SampleDesc.Count = 1; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.BufferCount = data->num_backbuffers; + desc.OutputWindow = hwnd; + desc.Windowed = TRUE; + desc.SwapEffect = effect; + desc.Flags = flags; + + return space; +} + +void gs_device::InitFactory() +{ + HRESULT hr = CreateDXGIFactory2(0, IID_PPV_ARGS(&factory)); + if (FAILED(hr)) + throw UnsupportedHWError("Failed to create DXGIFactory6", hr); +} + +void gs_device::InitAdapter(uint32_t adapterIdx) +{ + HRESULT hr = factory->EnumAdapterByGpuPreference( + adapterIdx, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, + IID_PPV_ARGS(&adapter)); + if (FAILED(hr)) + throw UnsupportedHWError("Failed to enumerate DXGIAdapter4", hr); +} + +bool gs_device::HasBadNV12Output() +try { + return false; +} catch (const HRError &error) { + blog(LOG_WARNING, "HasBadNV12Output failed: %s (%08lX)", error.str, + error.hr); + return false; +} catch (const char *error) { + blog(LOG_WARNING, "HasBadNV12Output failed: %s", error); + return false; +} + +void gs_device::InitDevice(uint32_t adapterIdx) { + DXGI_ADAPTER_DESC3 desc; + HRESULT hr = adapter->GetDesc3(&desc); + if (hr != S_OK) { + throw UnsupportedHWError("Adapter4 Failed to GetDesc", hr); + } + // todo log desc info + hr = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_12_2, IID_PPV_ARGS(&device)); + if (FAILED(hr)) { + throw UnsupportedHWError("Failed to D3D12CreateDevice", hr); + } +} + +void gs_device::UpdatePipelineState() { + +} + + +void gs_device::UpdateViewProjMatrix() +{ + gs_matrix_get(&curViewMatrix); + + /* negate Z col of the view matrix for right-handed coordinate system */ + curViewMatrix.x.z = -curViewMatrix.x.z; + curViewMatrix.y.z = -curViewMatrix.y.z; + curViewMatrix.z.z = -curViewMatrix.z.z; + curViewMatrix.t.z = -curViewMatrix.t.z; + + matrix4_mul(&curViewProjMatrix, &curViewMatrix, &curProjMatrix); + matrix4_transpose(&curViewProjMatrix, &curViewProjMatrix); +} + +void gs_device::FlushOutputViews() {} + +gs_device::gs_device(uint32_t adapterIdx) + : curToplogy(D3D_PRIMITIVE_TOPOLOGY_UNDEFINED) +{ + matrix4_identity(&curProjMatrix); + matrix4_identity(&curViewMatrix); + matrix4_identity(&curViewProjMatrix); + + memset(&viewport, 0, sizeof(viewport)); + + for (size_t i = 0; i < GS_MAX_TEXTURES; i++) { + curTextures[i] = NULL; + curSamplers[i] = NULL; + } + + InitFactory(); + InitAdapter(adapterIdx); + InitDevice(adapterIdx); + device_set_render_target(this, NULL, NULL); +} + +gs_device::~gs_device() {} + +const char *device_get_name(void) +{ + return "Direct3D 12"; +} + +int device_get_type(void) +{ + return GS_DEVICE_DIRECT3D_12; +} + +const char *device_preprocessor_name(void) +{ + return "_D3D12"; +} + +int device_create(gs_device_t **p_device, uint32_t adapter) +{ + gs_device *device = NULL; + int errorcode = GS_SUCCESS; + + try { + blog(LOG_INFO, "----------------------------------"); + blog(LOG_INFO, "Initializing D3D12..."); + device = new gs_device(adapter); + } catch (const UnsupportedHWError &error) { + blog(LOG_ERROR, "device_create (D3D12): %s (%08lX)", error.str, + error.hr); + errorcode = GS_ERROR_NOT_SUPPORTED; + + } catch (const HRError &error) { + blog(LOG_ERROR, "device_create (D3D12): %s (%08lX)", error.str, + error.hr); + errorcode = GS_ERROR_FAIL; + } + + *p_device = device; + return errorcode; +} + +void device_destroy(gs_device_t *device) +{ + delete device; +} + +void device_enter_context(gs_device_t *device) +{ + /* does nothing */ + UNUSED_PARAMETER(device); +} + +void device_leave_context(gs_device_t *device) +{ + /* does nothing */ + UNUSED_PARAMETER(device); +} + +void *device_get_device_obj(gs_device_t *device) +{ + return (void *)device->device.Get(); +} + +gs_swapchain_t *device_swapchain_create(gs_device_t *device, + const struct gs_init_data *data) +{ + /* not implement */ + return nullptr; +} + +void device_resize(gs_device_t *device, uint32_t cx, uint32_t cy) +{ + /* not implement */ +} + +enum gs_color_space device_get_color_space(gs_device_t *device) +{ + /* not implement */ + return gs_color_space::GS_CS_SRGB; +} + +void device_update_color_space(gs_device_t *device) +{ + /* not implement */ +} + +void device_get_size(const gs_device_t *device, uint32_t *cx, uint32_t *cy) +{ + /* not implement */ +} + +uint32_t device_get_width(const gs_device_t *device) +{ + /* not implement */ + return 0; +} + +uint32_t device_get_height(const gs_device_t *device) +{ + /* not implement */ + return 0; +} + +gs_texture_t *device_texture_create(gs_device_t *device, uint32_t width, + uint32_t height, + enum gs_color_format color_format, + uint32_t levels, const uint8_t **data, + uint32_t flags) +{ + /* not implement */ + return nullptr; +} + +gs_texture_t *device_cubetexture_create(gs_device_t *device, uint32_t size, + enum gs_color_format color_format, + uint32_t levels, const uint8_t **data, + uint32_t flags) +{ + /* not implement */ + return nullptr; +} + +gs_texture_t *device_voltexture_create(gs_device_t *device, uint32_t width, + uint32_t height, uint32_t depth, + enum gs_color_format color_format, + uint32_t levels, + const uint8_t *const *data, + uint32_t flags) +{ + /* not implement */ + return nullptr; +} + +gs_zstencil_t *device_zstencil_create(gs_device_t *device, uint32_t width, + uint32_t height, + enum gs_zstencil_format format) +{ + /* not implement */ + return nullptr; +} + +gs_stagesurf_t *device_stagesurface_create(gs_device_t *device, uint32_t width, + uint32_t height, + enum gs_color_format color_format) +{ + /* not implement */ + return nullptr; +} + +gs_samplerstate_t * +device_samplerstate_create(gs_device_t *device, + const struct gs_sampler_info *info) +{ + /* not implement */ + return nullptr; +} + +gs_shader_t *device_vertexshader_create(gs_device_t *device, + const char *shader_string, + const char *file, char **error_string) +{ + /* not implement */ + return nullptr; +} + +gs_shader_t *device_pixelshader_create(gs_device_t *device, + const char *shader_string, + const char *file, char **error_string) +{ + /* not implement */ + return nullptr; +} + +gs_vertbuffer_t *device_vertexbuffer_create(gs_device_t *device, + struct gs_vb_data *data, + uint32_t flags) +{ + /* not implement */ + return nullptr; +} + +gs_indexbuffer_t *device_indexbuffer_create(gs_device_t *device, + enum gs_index_type type, + void *indices, size_t num, + uint32_t flags) +{ /* not implement */ + return nullptr; +} + +gs_timer_t *device_timer_create(gs_device_t *device) +{ + /* not implement */ + return nullptr; +} + +gs_timer_range_t *device_timer_range_create(gs_device_t *device) +{ + /* not implement */ + return nullptr; +} + +enum gs_texture_type device_get_texture_type(const gs_texture_t *texture) +{ + /* not implement */ + return gs_texture_type::GS_TEXTURE_2D; +} + +void gs_device::LoadVertexBufferData() {} + +void device_load_vertexbuffer(gs_device_t *device, gs_vertbuffer_t *vertbuffer) +{ + /* not implement */ +} + +void device_load_indexbuffer(gs_device_t *device, gs_indexbuffer_t *indexbuffer) +{ + /* not implement */ +} + +void device_load_texture(gs_device_t *device, gs_texture_t *tex, int unit) +{ + /* not implement */ +} + +void device_load_texture_srgb(gs_device_t *device, gs_texture_t *tex, int unit) +{ + /* not implement */ +} + +void device_load_samplerstate(gs_device_t *device, + gs_samplerstate_t *samplerstate, int unit) +{ + /* not implement */ +} + +void device_load_vertexshader(gs_device_t *device, gs_shader_t *vertshader) +{ + /* not implement */ +} + +void device_load_pixelshader(gs_device_t *device, gs_shader_t *pixelshader) +{ + /* not implement */ +} + +void device_load_default_samplerstate(gs_device_t *device, bool b_3d, int unit) +{ + /* TODO */ + UNUSED_PARAMETER(device); + UNUSED_PARAMETER(b_3d); + UNUSED_PARAMETER(unit); +} + +gs_shader_t *device_get_vertex_shader(const gs_device_t *device) +{ + return device->curVertexShader; +} + +gs_shader_t *device_get_pixel_shader(const gs_device_t *device) +{ + return device->curPixelShader; +} + +gs_texture_t *device_get_render_target(const gs_device_t *device) +{ + if (device->curRenderTarget == &device->curSwapChain->target) + return NULL; + + return device->curRenderTarget; +} + +gs_zstencil_t *device_get_zstencil_target(const gs_device_t *device) +{ + if (device->curZStencilBuffer == &device->curSwapChain->zs) + return NULL; + + return device->curZStencilBuffer; +} + +void device_set_render_target(gs_device_t *device, gs_texture_t *tex, + gs_zstencil_t *zstencil) +{ + /* not implement */ +} + +void device_set_render_target_with_color_space(gs_device_t *device, + gs_texture_t *tex, + gs_zstencil_t *zstencil, + enum gs_color_space space) +{ + /* not implement */ +} + +void device_set_cube_render_target(gs_device_t *device, gs_texture_t *tex, + int side, gs_zstencil_t *zstencil) +{ + /* not implement */ +} + +void device_enable_framebuffer_srgb(gs_device_t *device, bool enable) +{ + /* not implement */ +} + +bool device_framebuffer_srgb_enabled(gs_device_t *device) +{ + return device->curFramebufferSrgb; +} +void device_copy_texture_region(gs_device_t *device, gs_texture_t *dst, + uint32_t dst_x, uint32_t dst_y, + gs_texture_t *src, uint32_t src_x, + uint32_t src_y, uint32_t src_w, uint32_t src_h) +{ + /* not implement */ +} + +void device_copy_texture(gs_device_t *device, gs_texture_t *dst, + gs_texture_t *src) +{ + device_copy_texture_region(device, dst, 0, 0, src, 0, 0, 0, 0); +} + +void device_stage_texture(gs_device_t *device, gs_stagesurf_t *dst, + gs_texture_t *src) +{ + /* not implement */ +} + +void device_begin_frame(gs_device_t *device) +{ + /* not implement */ +} + +void device_begin_scene(gs_device_t *device) +{ + /* not implement */ +} + +void device_draw(gs_device_t *device, enum gs_draw_mode draw_mode, + uint32_t start_vert, uint32_t num_verts) +{ + /* not implement */ +} + +void device_end_scene(gs_device_t *device) +{ + /* does nothing in D3D11 */ + UNUSED_PARAMETER(device); +} + +void device_load_swapchain(gs_device_t *device, gs_swapchain_t *swapchain) +{ + /* not implement */ +} + +void device_clear(gs_device_t *device, uint32_t clear_flags, + const struct vec4 *color, float depth, uint8_t stencil) +{ + /* not implement */ +} + +bool device_is_present_ready(gs_device_t *device) +{ + /* not implement */ + return false; +} + +void device_present(gs_device_t *device) +{ + /* not implement */ +} + +void device_flush(gs_device_t *device) +{ + /* not implement */ +} + +void device_set_cull_mode(gs_device_t *device, enum gs_cull_mode mode) +{ + /* not implement */ +} + +enum gs_cull_mode device_get_cull_mode(const gs_device_t *device) +{ + /* not implement */ + return gs_cull_mode::GS_NEITHER; +} + +void device_enable_blending(gs_device_t *device, bool enable) +{ + /* not implement */ +} + +void device_enable_depth_test(gs_device_t *device, bool enable) +{ + /* not implement */ +} + +void device_enable_stencil_test(gs_device_t *device, bool enable) +{ + /* not implement */ +} + +void device_enable_stencil_write(gs_device_t *device, bool enable) +{ + /* not implement */ +} + +void device_enable_color(gs_device_t *device, bool red, bool green, bool blue, + bool alpha) +{ + /* not implement */ +} + +void device_blend_function(gs_device_t *device, enum gs_blend_type src, + enum gs_blend_type dest) +{ + /* not implement */ +} + +void device_blend_function_separate(gs_device_t *device, + enum gs_blend_type src_c, + enum gs_blend_type dest_c, + enum gs_blend_type src_a, + enum gs_blend_type dest_a) +{ + /* not implement */ +} + +void device_blend_op(gs_device_t *device, enum gs_blend_op_type op) +{ + /* not implement */ +} + +void device_depth_function(gs_device_t *device, enum gs_depth_test test) +{ + /* not implement */ +} + +static inline void update_stencilside_test(gs_device_t *device, + StencilSide &side, + gs_depth_test test) +{ + /* not implement */ +} + +void device_stencil_function(gs_device_t *device, enum gs_stencil_side side, + enum gs_depth_test test) +{ + /* not implement */ +} + +static inline void update_stencilside_op(gs_device_t *device, StencilSide &side, + enum gs_stencil_op_type fail, + enum gs_stencil_op_type zfail, + enum gs_stencil_op_type zpass) +{ + /* not implement */ +} + +void device_stencil_op(gs_device_t *device, enum gs_stencil_side side, + enum gs_stencil_op_type fail, + enum gs_stencil_op_type zfail, + enum gs_stencil_op_type zpass) +{ + /* not implement */ +} + +void device_set_viewport(gs_device_t *device, int x, int y, int width, + int height) +{ + /* not implement */ +} + +void device_get_viewport(const gs_device_t *device, struct gs_rect *rect) +{ + memcpy(rect, &device->viewport, sizeof(gs_rect)); +} + +void device_set_scissor_rect(gs_device_t *device, const struct gs_rect *rect) +{ + /* not implement */ +} + +void device_ortho(gs_device_t *device, float left, float right, float top, + float bottom, float zNear, float zFar) +{ + matrix4 *dst = &device->curProjMatrix; + + float rml = right - left; + float bmt = bottom - top; + float fmn = zFar - zNear; + + vec4_zero(&dst->x); + vec4_zero(&dst->y); + vec4_zero(&dst->z); + vec4_zero(&dst->t); + + dst->x.x = 2.0f / rml; + dst->t.x = (left + right) / -rml; + + dst->y.y = 2.0f / -bmt; + dst->t.y = (bottom + top) / bmt; + + dst->z.z = 1.0f / fmn; + dst->t.z = zNear / -fmn; + + dst->t.w = 1.0f; +} + +void device_frustum(gs_device_t *device, float left, float right, float top, + float bottom, float zNear, float zFar) +{ + matrix4 *dst = &device->curProjMatrix; + + float rml = right - left; + float bmt = bottom - top; + float fmn = zFar - zNear; + float nearx2 = 2.0f * zNear; + + vec4_zero(&dst->x); + vec4_zero(&dst->y); + vec4_zero(&dst->z); + vec4_zero(&dst->t); + + dst->x.x = nearx2 / rml; + dst->z.x = (left + right) / -rml; + + dst->y.y = nearx2 / -bmt; + dst->z.y = (bottom + top) / bmt; + + dst->z.z = zFar / fmn; + dst->t.z = (zNear * zFar) / -fmn; + + dst->z.w = 1.0f; +} + +void device_projection_push(gs_device_t *device) +{ + mat4float mat; + memcpy(&mat, &device->curProjMatrix, sizeof(matrix4)); + device->projStack.push_back(mat); +} + +void device_projection_pop(gs_device_t *device) +{ + if (device->projStack.empty()) + return; + + const mat4float &mat = device->projStack.back(); + memcpy(&device->curProjMatrix, &mat, sizeof(matrix4)); + device->projStack.pop_back(); +} + +void gs_swapchain_destroy(gs_swapchain_t *swapchain) +{ + if (swapchain->device->curSwapChain == swapchain) + device_load_swapchain(swapchain->device, nullptr); + + delete swapchain; +} + +void gs_texture_destroy(gs_texture_t *tex) +{ + delete tex; +} + +uint32_t gs_texture_get_width(const gs_texture_t *tex) +{ + /* not implement */ + return 0; +} + +uint32_t gs_texture_get_height(const gs_texture_t *tex) +{ + /* not implement */ + return 0; +} + +enum gs_color_format gs_texture_get_color_format(const gs_texture_t *tex) +{ + if (tex->type != GS_TEXTURE_2D) + return GS_UNKNOWN; + + return static_cast(tex)->format; +} + +bool gs_texture_map(gs_texture_t *tex, uint8_t **ptr, uint32_t *linesize) +{ + /* not implement */ + return false; +} + +void gs_texture_unmap(gs_texture_t *tex) +{ + /* not implement */ +} + +void *gs_texture_get_obj(gs_texture_t *tex) +{ + /* not implement */ + return nullptr; +} + +void gs_cubetexture_destroy(gs_texture_t *cubetex) +{ + delete cubetex; +} + +uint32_t gs_cubetexture_get_size(const gs_texture_t *cubetex) +{ + /* not implement */ + return 0; +} + +enum gs_color_format +gs_cubetexture_get_color_format(const gs_texture_t *cubetex) +{ + if (cubetex->type != GS_TEXTURE_CUBE) + return GS_UNKNOWN; + + const gs_texture_2d *tex = static_cast(cubetex); + return tex->format; +} + +void gs_voltexture_destroy(gs_texture_t *voltex) +{ + delete voltex; +} + +uint32_t gs_voltexture_get_width(const gs_texture_t *voltex) +{ + /* TODO */ + UNUSED_PARAMETER(voltex); + return 0; +} + +uint32_t gs_voltexture_get_height(const gs_texture_t *voltex) +{ + /* TODO */ + UNUSED_PARAMETER(voltex); + return 0; +} + +uint32_t gs_voltexture_get_depth(const gs_texture_t *voltex) +{ + /* TODO */ + UNUSED_PARAMETER(voltex); + return 0; +} + +enum gs_color_format gs_voltexture_get_color_format(const gs_texture_t *voltex) +{ + /* TODO */ + UNUSED_PARAMETER(voltex); + return GS_UNKNOWN; +} + +void gs_stagesurface_destroy(gs_stagesurf_t *stagesurf) +{ + delete stagesurf; +} + +uint32_t gs_stagesurface_get_width(const gs_stagesurf_t *stagesurf) +{ + return stagesurf->width; +} + +uint32_t gs_stagesurface_get_height(const gs_stagesurf_t *stagesurf) +{ + return stagesurf->height; +} + +enum gs_color_format +gs_stagesurface_get_color_format(const gs_stagesurf_t *stagesurf) +{ + return stagesurf->format; +} + +bool gs_stagesurface_map(gs_stagesurf_t *stagesurf, uint8_t **data, + uint32_t *linesize) +{ + /* not implement */ + return true; +} + +void gs_stagesurface_unmap(gs_stagesurf_t *stagesurf) +{ + /* not implement */ +} + +void gs_zstencil_destroy(gs_zstencil_t *zstencil) +{ + /* not implement */ +} + +void gs_samplerstate_destroy(gs_samplerstate_t *samplerstate) +{ + /* not implement */ +} + +void gs_vertexbuffer_destroy(gs_vertbuffer_t *vertbuffer) +{ + if (vertbuffer && vertbuffer->device->lastVertexBuffer == vertbuffer) + vertbuffer->device->lastVertexBuffer = nullptr; + delete vertbuffer; +} + +static inline void gs_vertexbuffer_flush_internal(gs_vertbuffer_t *vertbuffer, + const gs_vb_data *data) +{ + /* not implement */ +} + +void gs_vertexbuffer_flush(gs_vertbuffer_t *vertbuffer) +{ + /* not implement */ +} + +void gs_vertexbuffer_flush_direct(gs_vertbuffer_t *vertbuffer, + const gs_vb_data *data) +{ + gs_vertexbuffer_flush_internal(vertbuffer, data); +} + +struct gs_vb_data *gs_vertexbuffer_get_data(const gs_vertbuffer_t *vertbuffer) +{ + /* not implement */ + return nullptr; +} + +void gs_indexbuffer_destroy(gs_indexbuffer_t *indexbuffer) +{ + delete indexbuffer; +} + +static inline void gs_indexbuffer_flush_internal(gs_indexbuffer_t *indexbuffer, + const void *data) +{ + /* not implement */ +} + +void gs_indexbuffer_flush(gs_indexbuffer_t *indexbuffer) +{ + /* not implement */ +} + +void gs_indexbuffer_flush_direct(gs_indexbuffer_t *indexbuffer, + const void *data) +{ + gs_indexbuffer_flush_internal(indexbuffer, data); +} + +void *gs_indexbuffer_get_data(const gs_indexbuffer_t *indexbuffer) +{ + /* not implement */ + return nullptr; +} + +size_t gs_indexbuffer_get_num_indices(const gs_indexbuffer_t *indexbuffer) +{ + /* not implement */ + return 0; +} + +enum gs_index_type gs_indexbuffer_get_type(const gs_indexbuffer_t *indexbuffer) +{ + /* not implement */ + return gs_index_type::GS_UNSIGNED_LONG; +} + +void gs_timer_destroy(gs_timer_t *timer) +{ + /* not implement */ +} + +void gs_timer_begin(gs_timer_t *timer) +{ + /* not implement */ +} + +void gs_timer_end(gs_timer_t *timer) +{ + /* not implement */ +} + +bool gs_timer_get_data(gs_timer_t *timer, uint64_t *ticks) +{ + /* not implement */ + return false; +} + +void gs_timer_range_destroy(gs_timer_range_t *range) +{ + delete range; +} + +void gs_timer_range_begin(gs_timer_range_t *range) +{ + /* not implement */ +} + +void gs_timer_range_end(gs_timer_range_t *range) +{ + /* not implement */ +} + +bool gs_timer_range_get_data(gs_timer_range_t *range, bool *disjoint, + uint64_t *frequency) +{ + /* not implement */ + return false; +} + +gs_timer::gs_timer(gs_device_t *device) : gs_obj(device, gs_type::gs_timer) +{ + /* not implement */ +} + +gs_timer_range::gs_timer_range(gs_device_t *device) + : gs_obj(device, gs_type::gs_timer_range) +{ + /* not implement */ +} + +extern "C" EXPORT bool device_gdi_texture_available(void) +{ + return true; +} + +extern "C" EXPORT bool device_shared_texture_available(void) +{ + return true; +} + +extern "C" EXPORT bool device_nv12_available(gs_device_t *device) +{ + return device->nv12Supported; +} + +extern "C" EXPORT bool device_p010_available(gs_device_t *device) +{ + return device->p010Supported; +} + +extern "C" EXPORT bool device_is_monitor_hdr(gs_device_t *device, void *monitor) +{ + /* not implement */ + return false; +} + +extern "C" EXPORT void device_debug_marker_begin(gs_device_t *, + const char *markername, + const float color[4]) +{ + /* not implement */ +} + +extern "C" EXPORT void device_debug_marker_end(gs_device_t *) +{ + /* not implement */ +} + +extern "C" EXPORT gs_texture_t * +device_texture_create_gdi(gs_device_t *device, uint32_t width, uint32_t height) +{ + /* not implement */ + return nullptr; +} + +static inline bool TextureGDICompatible(gs_texture_2d *tex2d, const char *func) +{ + /* not implement */ + return false; +} + +extern "C" EXPORT void *gs_texture_get_dc(gs_texture_t *tex) +{ + /* not implement */ + return nullptr; +} + +extern "C" EXPORT void gs_texture_release_dc(gs_texture_t *tex) +{ + /* not implement */ +} + +extern "C" EXPORT gs_texture_t *device_texture_open_shared(gs_device_t *device, + uint32_t handle) +{ + /* not implement */ + return nullptr; +} + +extern "C" EXPORT gs_texture_t * +device_texture_open_nt_shared(gs_device_t *device, uint32_t handle) +{ + /* not implement */ + return nullptr; +} + +extern "C" EXPORT uint32_t device_texture_get_shared_handle(gs_texture_t *tex) +{ + /* not implement */ + return 0; +} + +extern "C" EXPORT gs_texture_t *device_texture_wrap_obj(gs_device_t *device, + void *obj) +{ + /* not implement */ + return nullptr; +} + +int device_texture_acquire_sync(gs_texture_t *tex, uint64_t key, uint32_t ms) +{ + /* not implement */ + return 0; +} + +extern "C" EXPORT int device_texture_release_sync(gs_texture_t *tex, + uint64_t key) +{ + /* not implement */ + + return -1; +} + +extern "C" EXPORT bool +device_texture_create_nv12(gs_device_t *device, gs_texture_t **p_tex_y, + gs_texture_t **p_tex_uv, uint32_t width, + uint32_t height, uint32_t flags) +{ + /* not implement */ + return true; +} + +extern "C" EXPORT bool +device_texture_create_p010(gs_device_t *device, gs_texture_t **p_tex_y, + gs_texture_t **p_tex_uv, uint32_t width, + uint32_t height, uint32_t flags) +{ + /* not implement */ + return true; +} + +extern "C" EXPORT gs_stagesurf_t * +device_stagesurface_create_nv12(gs_device_t *device, uint32_t width, + uint32_t height) +{ + /* not implement */ + return nullptr; +} + +extern "C" EXPORT gs_stagesurf_t * +device_stagesurface_create_p010(gs_device_t *device, uint32_t width, + uint32_t height) +{ + /* not implement */ + return nullptr; +} + +extern "C" EXPORT void +device_register_loss_callbacks(gs_device_t *device, + const gs_device_loss *callbacks) +{ + /* not implement */ +} + +extern "C" EXPORT void device_unregister_loss_callbacks(gs_device_t *device, + void *data) +{ + /* not implement */ +} + +uint32_t gs_get_adapter_count(void) +{ + /* not implement */ + return 0; +} + +extern "C" EXPORT bool device_can_adapter_fast_clear(gs_device_t *device) +{ + /* not implement */ + return false; +} diff --git a/libobs-d3d12/d3d12-subsystem.hpp b/libobs-d3d12/d3d12-subsystem.hpp new file mode 100644 index 00000000000000..2774a852126f99 --- /dev/null +++ b/libobs-d3d12/d3d12-subsystem.hpp @@ -0,0 +1,726 @@ +/****************************************************************************** + Copyright (C) 2023 by Lain Bailey + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +******************************************************************************/ + +#pragma once + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +// TODO(wanhongqing) libobs-d3d11 and libobs-d3d12 need clean +static inline uint32_t GetWinVer() +{ + struct win_version_info ver; + get_win_ver(&ver); + + return (ver.major << 8) | ver.minor; +} + +static inline DXGI_FORMAT ConvertGSTextureFormatResource(gs_color_format format) +{ + switch (format) { + case GS_UNKNOWN: + return DXGI_FORMAT_UNKNOWN; + case GS_A8: + return DXGI_FORMAT_A8_UNORM; + case GS_R8: + return DXGI_FORMAT_R8_UNORM; + case GS_RGBA: + return DXGI_FORMAT_R8G8B8A8_TYPELESS; + case GS_BGRX: + return DXGI_FORMAT_B8G8R8X8_TYPELESS; + case GS_BGRA: + return DXGI_FORMAT_B8G8R8A8_TYPELESS; + case GS_R10G10B10A2: + return DXGI_FORMAT_R10G10B10A2_UNORM; + case GS_RGBA16: + return DXGI_FORMAT_R16G16B16A16_UNORM; + case GS_R16: + return DXGI_FORMAT_R16_UNORM; + case GS_RGBA16F: + return DXGI_FORMAT_R16G16B16A16_FLOAT; + case GS_RGBA32F: + return DXGI_FORMAT_R32G32B32A32_FLOAT; + case GS_RG16F: + return DXGI_FORMAT_R16G16_FLOAT; + case GS_RG32F: + return DXGI_FORMAT_R32G32_FLOAT; + case GS_R16F: + return DXGI_FORMAT_R16_FLOAT; + case GS_R32F: + return DXGI_FORMAT_R32_FLOAT; + case GS_DXT1: + return DXGI_FORMAT_BC1_UNORM; + case GS_DXT3: + return DXGI_FORMAT_BC2_UNORM; + case GS_DXT5: + return DXGI_FORMAT_BC3_UNORM; + case GS_R8G8: + return DXGI_FORMAT_R8G8_UNORM; + case GS_RGBA_UNORM: + return DXGI_FORMAT_R8G8B8A8_UNORM; + case GS_BGRX_UNORM: + return DXGI_FORMAT_B8G8R8X8_UNORM; + case GS_BGRA_UNORM: + return DXGI_FORMAT_B8G8R8A8_UNORM; + case GS_RG16: + return DXGI_FORMAT_R16G16_UNORM; + } + + return DXGI_FORMAT_UNKNOWN; +} + +static inline DXGI_FORMAT ConvertGSTextureFormatView(gs_color_format format) +{ + switch (format) { + case GS_RGBA: + return DXGI_FORMAT_R8G8B8A8_UNORM; + case GS_BGRX: + return DXGI_FORMAT_B8G8R8X8_UNORM; + case GS_BGRA: + return DXGI_FORMAT_B8G8R8A8_UNORM; + default: + return ConvertGSTextureFormatResource(format); + } +} + +static inline DXGI_FORMAT +ConvertGSTextureFormatViewLinear(gs_color_format format) +{ + switch (format) { + case GS_RGBA: + return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + case GS_BGRX: + return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; + case GS_BGRA: + return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + default: + return ConvertGSTextureFormatResource(format); + } +} + +static inline gs_color_format ConvertDXGITextureFormat(DXGI_FORMAT format) +{ + switch (format) { + case DXGI_FORMAT_A8_UNORM: + return GS_A8; + case DXGI_FORMAT_R8_UNORM: + return GS_R8; + case DXGI_FORMAT_R8G8_UNORM: + return GS_R8G8; + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + return GS_RGBA; + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + return GS_BGRX; + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + return GS_BGRA; + case DXGI_FORMAT_R10G10B10A2_UNORM: + return GS_R10G10B10A2; + case DXGI_FORMAT_R16G16B16A16_UNORM: + return GS_RGBA16; + case DXGI_FORMAT_R16_UNORM: + return GS_R16; + case DXGI_FORMAT_R16G16B16A16_FLOAT: + return GS_RGBA16F; + case DXGI_FORMAT_R32G32B32A32_FLOAT: + return GS_RGBA32F; + case DXGI_FORMAT_R16G16_FLOAT: + return GS_RG16F; + case DXGI_FORMAT_R32G32_FLOAT: + return GS_RG32F; + case DXGI_FORMAT_R16_FLOAT: + return GS_R16F; + case DXGI_FORMAT_R32_FLOAT: + return GS_R32F; + case DXGI_FORMAT_BC1_UNORM: + return GS_DXT1; + case DXGI_FORMAT_BC2_UNORM: + return GS_DXT3; + case DXGI_FORMAT_BC3_UNORM: + return GS_DXT5; + case DXGI_FORMAT_R8G8B8A8_UNORM: + return GS_RGBA_UNORM; + case DXGI_FORMAT_B8G8R8X8_UNORM: + return GS_BGRX_UNORM; + case DXGI_FORMAT_B8G8R8A8_UNORM: + return GS_BGRA_UNORM; + case DXGI_FORMAT_R16G16_UNORM: + return GS_RG16; + } + + return GS_UNKNOWN; +} + +static inline DXGI_FORMAT ConvertGSZStencilFormat(gs_zstencil_format format) +{ + switch (format) { + case GS_ZS_NONE: + return DXGI_FORMAT_UNKNOWN; + case GS_Z16: + return DXGI_FORMAT_D16_UNORM; + case GS_Z24_S8: + return DXGI_FORMAT_D24_UNORM_S8_UINT; + case GS_Z32F: + return DXGI_FORMAT_D32_FLOAT; + case GS_Z32F_S8X24: + return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; + } + + return DXGI_FORMAT_UNKNOWN; +} + +static inline D3D12_COMPARISON_FUNC ConvertGSDepthTest(gs_depth_test test) +{ + switch (test) { + case GS_NEVER: + return D3D12_COMPARISON_FUNC_NEVER; + case GS_LESS: + return D3D12_COMPARISON_FUNC_LESS; + case GS_LEQUAL: + return D3D12_COMPARISON_FUNC_EQUAL; + case GS_EQUAL: + return D3D12_COMPARISON_FUNC_EQUAL; + case GS_GEQUAL: + return D3D12_COMPARISON_FUNC_GREATER_EQUAL; + case GS_GREATER: + return D3D12_COMPARISON_FUNC_GREATER; + case GS_NOTEQUAL: + return D3D12_COMPARISON_FUNC_NOT_EQUAL; + case GS_ALWAYS: + return D3D12_COMPARISON_FUNC_ALWAYS; + } + + return D3D12_COMPARISON_FUNC_NEVER; +} + +static inline D3D12_STENCIL_OP ConvertGSStencilOp(gs_stencil_op_type op) +{ + switch (op) { + case GS_KEEP: + return D3D12_STENCIL_OP_KEEP; + case GS_ZERO: + return D3D12_STENCIL_OP_ZERO; + case GS_REPLACE: + return D3D12_STENCIL_OP_REPLACE; + case GS_INCR: + return D3D12_STENCIL_OP_INCR; + case GS_DECR: + return D3D12_STENCIL_OP_DECR; + case GS_INVERT: + return D3D12_STENCIL_OP_INVERT; + } + + return D3D12_STENCIL_OP_KEEP; +} + +static inline D3D12_BLEND ConvertGSBlendType(gs_blend_type type) +{ + switch (type) { + case GS_BLEND_ZERO: + return D3D12_BLEND_ZERO; + case GS_BLEND_ONE: + return D3D12_BLEND_ONE; + case GS_BLEND_SRCCOLOR: + return D3D12_BLEND_SRC_COLOR; + case GS_BLEND_INVSRCCOLOR: + return D3D12_BLEND_INV_SRC_COLOR; + case GS_BLEND_SRCALPHA: + return D3D12_BLEND_SRC_ALPHA; + case GS_BLEND_INVSRCALPHA: + return D3D12_BLEND_INV_SRC_ALPHA; + case GS_BLEND_DSTCOLOR: + return D3D12_BLEND_DEST_COLOR; + case GS_BLEND_INVDSTCOLOR: + return D3D12_BLEND_INV_DEST_COLOR; + case GS_BLEND_DSTALPHA: + return D3D12_BLEND_DEST_ALPHA; + case GS_BLEND_INVDSTALPHA: + return D3D12_BLEND_INV_DEST_ALPHA; + case GS_BLEND_SRCALPHASAT: + return D3D12_BLEND_SRC_ALPHA_SAT; + } + + return D3D12_BLEND_ONE; +} + +static inline D3D12_BLEND_OP ConvertGSBlendOpType(gs_blend_op_type type) +{ + switch (type) { + case GS_BLEND_OP_ADD: + return D3D12_BLEND_OP_ADD; + case GS_BLEND_OP_SUBTRACT: + return D3D12_BLEND_OP_SUBTRACT; + case GS_BLEND_OP_REVERSE_SUBTRACT: + return D3D12_BLEND_OP_REV_SUBTRACT; + case GS_BLEND_OP_MIN: + return D3D12_BLEND_OP_MIN; + case GS_BLEND_OP_MAX: + return D3D12_BLEND_OP_MAX; + } + + return D3D12_BLEND_OP_ADD; +} + +static inline D3D12_CULL_MODE ConvertGSCullMode(gs_cull_mode mode) +{ + switch (mode) { + case GS_BACK: + return D3D12_CULL_MODE_BACK; + case GS_FRONT: + return D3D12_CULL_MODE_FRONT; + case GS_NEITHER: + return D3D12_CULL_MODE_NONE; + } + + return D3D12_CULL_MODE_BACK; +} + +static inline D3D12_PRIMITIVE_TOPOLOGY ConvertGSTopology(gs_draw_mode mode) +{ + switch (mode) { + case GS_POINTS: + return D3D_PRIMITIVE_TOPOLOGY_POINTLIST; + case GS_LINES: + return D3D_PRIMITIVE_TOPOLOGY_LINELIST; + case GS_LINESTRIP: + return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; + case GS_TRIS: + return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + case GS_TRISTRIP: + return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; + } + + return D3D_PRIMITIVE_TOPOLOGY_POINTLIST; +} + +/* exception-safe RAII wrapper for vertex buffer data (NOTE: not copy-safe) */ +struct VBDataPtr { + gs_vb_data *data; + + inline VBDataPtr(gs_vb_data *data) : data(data) {} + inline ~VBDataPtr() { gs_vbdata_destroy(data); } +}; + +enum class gs_type { + gs_vertex_buffer, + gs_index_buffer, + gs_texture_2d, + gs_zstencil_buffer, + gs_stage_surface, + gs_sampler_state, + gs_vertex_shader, + gs_pixel_shader, + gs_duplicator, + gs_swap_chain, + gs_timer, + gs_timer_range, + gs_texture_3d, +}; + +struct gs_obj { + gs_device_t *device; + gs_type obj_type; + gs_obj *next; + gs_obj **prev_next; + + inline gs_obj() : device(nullptr), next(nullptr), prev_next(nullptr) {} + + gs_obj(gs_device_t *device, gs_type type); + virtual ~gs_obj(); +}; + +struct gs_vertex_buffer : gs_obj { + // todo + gs_vertex_buffer(gs_device_t *device, struct gs_vb_data *data, + uint32_t flags); +}; + +/* exception-safe RAII wrapper for index buffer data (NOTE: not copy-safe) */ +struct DataPtr { + void *data; + + inline DataPtr(void *data) : data(data) {} + inline ~DataPtr() { bfree(data); } +}; + +struct gs_index_buffer : gs_obj { + // todo + gs_index_buffer(gs_device_t *device, enum gs_index_type type, + void *indices, size_t num, uint32_t flags); +}; + +struct gs_timer : gs_obj { + // todo + gs_timer(gs_device_t *device); +}; + +struct gs_timer_range : gs_obj { + // todo + gs_timer_range(gs_device_t *device); +}; + +struct gs_texture : gs_obj { + gs_texture_type type; + uint32_t levels; + gs_color_format format; + // todo + inline gs_texture(gs_texture_type type, uint32_t levels, + gs_color_format format) + : type(type), + levels(levels), + format(format) + { + } + + inline gs_texture(gs_device *device, gs_type obj_type, + gs_texture_type type) + : gs_obj(device, obj_type), + type(type) + { + } + + inline gs_texture(gs_device *device, gs_type obj_type, + gs_texture_type type, uint32_t levels, + gs_color_format format) + : gs_obj(device, obj_type), + type(type), + levels(levels), + format(format) + { + } +}; + +struct gs_texture_2d : gs_texture { + // todo +}; + +struct gs_texture_3d : gs_texture { + // todo +}; + +struct gs_zstencil_buffer : gs_obj { + uint32_t width, height; + gs_zstencil_format format; + DXGI_FORMAT dxgiFormat; + // todo + gs_zstencil_buffer(gs_device_t *device, uint32_t width, uint32_t height, + gs_zstencil_format format); +}; + +struct gs_stage_surface : gs_obj { + uint32_t width, height; + gs_color_format format; + DXGI_FORMAT dxgiFormat; + // todo + gs_stage_surface(gs_device_t *device, uint32_t width, uint32_t height, + gs_color_format colorFormat); + gs_stage_surface(gs_device_t *device, uint32_t width, uint32_t height, + bool p010); +}; + +struct gs_sampler_state : gs_obj { + // todo + gs_sampler_state(gs_device_t *device, const gs_sampler_info *info); +}; + +struct gs_shader_param { + std::string name; + gs_shader_param_type type; + + uint32_t textureID; + struct gs_sampler_state *nextSampler = nullptr; + + int arrayCount; + + size_t pos; + + std::vector curValue; + std::vector defaultValue; + bool changed; +}; + +struct ShaderError { + ComPtr errors; + HRESULT hr; + + inline ShaderError(const ComPtr &errors, HRESULT hr) + : errors(errors), + hr(hr) + { + } +}; + +struct gs_shader : gs_obj { + gs_shader_type type; + std::vector params; + size_t constantSize; + void Compile(const char *shaderStr, const char *file, + const char *target, ID3D10Blob **shader); + + inline gs_shader(gs_device_t *device, gs_type obj_type, + gs_shader_type type) + : gs_obj(device, obj_type), + type(type), + constantSize(0) + { + } + + virtual ~gs_shader() {} +}; + +struct ShaderSampler { + std::string name; + gs_sampler_state sampler; + + inline ShaderSampler(const char *name, gs_device_t *device, + gs_sampler_info *info) + : name(name), + sampler(device, info) + { + } +}; + +struct gs_vertex_shader : gs_shader { + gs_vertex_shader(gs_device_t *device, const char *file, + const char *shaderString); +}; + +struct gs_pixel_shader : gs_shader { + gs_pixel_shader(gs_device_t *device, const char *file, + const char *shaderString); +}; + +struct gs_swap_chain : gs_obj { + HWND hwnd; + gs_init_data initData; + DXGI_SWAP_CHAIN_DESC1 swapDesc = {}; + gs_color_space space; + + gs_texture_2d target; + gs_zstencil_buffer zs; + ComPtr swap; + HANDLE hWaitable = NULL; + + void InitTarget(uint32_t cx, uint32_t cy); + void InitZStencilBuffer(uint32_t cx, uint32_t cy); + void Resize(uint32_t cx, uint32_t cy, gs_color_format format); + void Init(); + // todo + + gs_swap_chain(gs_device *device, const gs_init_data *data); + virtual ~gs_swap_chain(); +}; + +struct BlendState { + bool blendEnabled; + gs_blend_type srcFactorC; + gs_blend_type destFactorC; + gs_blend_type srcFactorA; + gs_blend_type destFactorA; + gs_blend_op_type op; + + bool redEnabled; + bool greenEnabled; + bool blueEnabled; + bool alphaEnabled; + + inline BlendState() + : blendEnabled(true), + srcFactorC(GS_BLEND_SRCALPHA), + destFactorC(GS_BLEND_INVSRCALPHA), + srcFactorA(GS_BLEND_ONE), + destFactorA(GS_BLEND_INVSRCALPHA), + op(GS_BLEND_OP_ADD), + redEnabled(true), + greenEnabled(true), + blueEnabled(true), + alphaEnabled(true) + { + } + + inline BlendState(const BlendState& state) + { + memcpy(this, &state, sizeof(BlendState)); + } +}; + + +struct StencilSide { + gs_depth_test test; + gs_stencil_op_type fail; + gs_stencil_op_type zfail; + gs_stencil_op_type zpass; + + inline StencilSide() + : test(GS_ALWAYS), + fail(GS_KEEP), + zfail(GS_KEEP), + zpass(GS_KEEP) + { + } +}; + +struct ZStencilState { + bool depthEnabled; + bool depthWriteEnabled; + gs_depth_test depthFunc; + + bool stencilEnabled; + bool stencilWriteEnabled; + StencilSide stencilFront; + StencilSide stencilBack; + + inline ZStencilState() + : depthEnabled(true), + depthWriteEnabled(true), + depthFunc(GS_LESS), + stencilEnabled(false), + stencilWriteEnabled(true) + { + } + + inline ZStencilState(const ZStencilState& state) + { + memcpy(this, &state, sizeof(ZStencilState)); + } +}; + +struct RasterState { + gs_cull_mode cullMode; + bool scissorEnabled; + + inline RasterState() : cullMode(GS_BACK), scissorEnabled(false) {} + + inline RasterState(const RasterState& state) + { + memcpy(this, &state, sizeof(RasterState)); + } +}; + +struct mat4float { + float mat[16]; +}; + +struct gs_monitor_color_info { + bool hdr; + UINT bits_per_color; + ULONG sdr_white_nits; + + gs_monitor_color_info(bool hdr, int bits_per_color, + ULONG sdr_white_nits) + : hdr(hdr), + bits_per_color(bits_per_color), + sdr_white_nits(sdr_white_nits) + { + } +}; + +struct SavedPipelineState { + ComPtr pipeline_state; + D3D12_GRAPHICS_PIPELINE_STATE_DESC desc; +}; + +struct gs_device { + ComPtr factory; + ComPtr adapter; + ComPtr device; + ComPtr commandQueue; + ComPtr context; + uint32_t adpIdx = 0; + bool nv12Supported = false; + bool p010Supported = false; + bool fastClearSupported = false; + + gs_texture_2d *curRenderTarget = nullptr; + gs_zstencil_buffer *curZStencilBuffer = nullptr; + int curRenderSide = 0; + enum gs_color_space curColorSpace = GS_CS_SRGB; + bool curFramebufferSrgb = false; + bool curFramebufferInvalidate = false; + gs_texture *curTextures[GS_MAX_TEXTURES]; + gs_sampler_state *curSamplers[GS_MAX_TEXTURES]; + gs_vertex_buffer *curVertexBuffer = nullptr; + gs_index_buffer *curIndexBuffer = nullptr; + gs_vertex_shader *curVertexShader = nullptr; + gs_pixel_shader *curPixelShader = nullptr; + gs_swap_chain *curSwapChain = nullptr; + + gs_vertex_buffer *lastVertexBuffer = nullptr; + gs_vertex_shader *lastVertexShader = nullptr; + + // pipeline state + bool zstencilStateChanged = true; + bool rasterStateChanged = true; + bool blendStateChanged = true; + ZStencilState zstencilState; + RasterState rasterState; + BlendState blendState; + std::vector SavedPipelineState; + D3D_PRIMITIVE_TOPOLOGY curToplogy; + ComPtr currentPipelineState; + + gs_rect viewport; + + std::vector projStack; + + matrix4 curProjMatrix; + matrix4 curViewMatrix; + matrix4 curViewProjMatrix; + + std::vector loss_callbacks; + gs_obj *first_obj = nullptr; + + std::vector> monitor_to_hdr; + + void InitFactory(); + void InitAdapter(uint32_t adapterIdx); + void InitDevice(uint32_t adapterIdx); + + void UpdatePipelineState(); + + void LoadVertexBufferData(); + + void UpdateViewProjMatrix(); + + void FlushOutputViews(); + + void RebuildDevice(); + + bool HasBadNV12Output(); + + gs_monitor_color_info GetMonitorColorInfo(HMONITOR hMonitor); + + gs_device(uint32_t adapterIdx); + ~gs_device(); +}; + +extern "C" EXPORT int device_texture_acquire_sync(gs_texture_t *tex, + uint64_t key, uint32_t ms); diff --git a/libobs/graphics/graphics.h b/libobs/graphics/graphics.h index 61d4a5ae5bd2b4..2618e90170ab99 100644 --- a/libobs/graphics/graphics.h +++ b/libobs/graphics/graphics.h @@ -499,6 +499,8 @@ struct gs_init_data { #define GS_DEVICE_OPENGL 1 #define GS_DEVICE_DIRECT3D_11 2 +// not implement +#define GS_DEVICE_DIRECT3D_12 2 EXPORT const char *gs_get_device_name(void); EXPORT int gs_get_device_type(void);