From 2a54cbca75379c48fc181359dfcd9c830be0658b Mon Sep 17 00:00:00 2001 From: aliaspider Date: Thu, 25 Jan 2018 04:57:49 +0100 Subject: [PATCH 1/4] (D3D11) autogen mipmaps when needed. --- gfx/common/d3d11_common.c | 28 +++++++++++--- gfx/common/d3d11_common.h | 31 ++++++++------- gfx/drivers/d3d11.c | 47 +++++++++++------------ gfx/drivers_font/d3d11_font.c | 17 ++------ menu/drivers_display/menu_display_d3d11.c | 8 ++-- 5 files changed, 70 insertions(+), 61 deletions(-) diff --git a/gfx/common/d3d11_common.c b/gfx/common/d3d11_common.c index bb913b8934..374bae0827 100644 --- a/gfx/common/d3d11_common.c +++ b/gfx/common/d3d11_common.c @@ -59,9 +59,6 @@ void d3d11_init_texture(D3D11Device device, d3d11_texture_t* texture) Release(texture->staging); Release(texture->view); - // .Usage = D3D11_USAGE_DYNAMIC, - // .CPUAccessFlags = D3D11_CPU_ACCESS_WRITE, - texture->desc.MipLevels = 1; texture->desc.ArraySize = 1; texture->desc.SampleDesc.Count = 1; @@ -69,7 +66,20 @@ void d3d11_init_texture(D3D11Device device, d3d11_texture_t* texture) texture->desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; texture->desc.CPUAccessFlags = texture->desc.Usage == D3D11_USAGE_DYNAMIC ? D3D11_CPU_ACCESS_WRITE : 0; - texture->desc.MiscFlags = 0; + + if (texture->desc.MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS) + { + texture->desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + unsigned width = texture->desc.Width >> 5; + unsigned height = texture->desc.Height >> 5; + while (width && height) + { + width >>= 1; + height >>= 1; + texture->desc.MipLevels++; + } + } + D3D11CreateTexture2D(device, &texture->desc, NULL, &texture->handle); { @@ -84,7 +94,9 @@ void d3d11_init_texture(D3D11Device device, d3d11_texture_t* texture) { D3D11_TEXTURE2D_DESC desc = texture->desc; + desc.MipLevels = 1; desc.BindFlags = 0; + desc.MiscFlags = 0; desc.Usage = D3D11_USAGE_STAGING; desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; D3D11CreateTexture2D(device, &desc, NULL, &texture->staging); @@ -101,6 +113,7 @@ void d3d11_update_texture( d3d11_texture_t* texture) { D3D11_MAPPED_SUBRESOURCE mapped_texture; + D3D11_BOX frame_box = { 0, 0, 0, width, height, 1 }; D3D11MapTexture2D(ctx, texture->staging, 0, D3D11_MAP_WRITE, 0, &mapped_texture); @@ -110,8 +123,11 @@ void d3d11_update_texture( D3D11UnmapTexture2D(ctx, texture->staging, 0); - if (texture->desc.Usage == D3D11_USAGE_DEFAULT) - texture->dirty = true; + D3D11CopyTexture2DSubresourceRegion( + ctx, texture->handle, 0, 0, 0, 0, texture->staging, 0, &frame_box); + + if (texture->desc.MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS) + D3D11GenerateMips(ctx, texture->view); } DXGI_FORMAT diff --git a/gfx/common/d3d11_common.h b/gfx/common/d3d11_common.h index d0e0dee20a..3220e83fef 100644 --- a/gfx/common/d3d11_common.h +++ b/gfx/common/d3d11_common.h @@ -2470,7 +2470,7 @@ typedef struct D3D11Texture2D staging; D3D11_TEXTURE2D_DESC desc; D3D11ShaderResourceView view; - bool dirty; + D3D11SamplerState sampler; } d3d11_texture_t; typedef struct @@ -2488,7 +2488,7 @@ typedef struct { float scaling; float rotation; - }params; + } params; } d3d11_sprite_t; typedef struct @@ -2519,20 +2519,18 @@ typedef struct bool resize_viewport; struct { - d3d11_texture_t texture; - D3D11Buffer vbo; - D3D11SamplerState sampler; - bool enabled; - bool fullscreen; + d3d11_texture_t texture; + D3D11Buffer vbo; + bool enabled; + bool fullscreen; } menu; struct { - d3d11_texture_t texture; - D3D11Buffer vbo; - D3D11Buffer ubo; - D3D11SamplerState sampler; - D3D11_VIEWPORT viewport; - int rotation; + d3d11_texture_t texture; + D3D11Buffer vbo; + D3D11Buffer ubo; + D3D11_VIEWPORT viewport; + int rotation; } frame; struct { @@ -2567,3 +2565,10 @@ d3d11_get_closest_match_texture2D(D3D11Device device, DXGI_FORMAT desired_format device, desired_format, D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE); } + +static inline d3d11_set_texture_and_sampler( + D3D11DeviceContext ctx, UINT slot, d3d11_texture_t* texture) +{ + D3D11SetPShaderResources(ctx, slot, 1, &texture->view); + D3D11SetPShaderSamplers(ctx, slot, 1, &texture->sampler); +} diff --git a/gfx/drivers/d3d11.c b/gfx/drivers/d3d11.c index ce675f1572..c5513a6bcf 100644 --- a/gfx/drivers/d3d11.c +++ b/gfx/drivers/d3d11.c @@ -35,9 +35,9 @@ static void d3d11_set_filtering(void* data, unsigned index, bool smooth) d3d11_video_t* d3d11 = (d3d11_video_t*)data; if (smooth) - d3d11->frame.sampler = d3d11->sampler_linear; + d3d11->frame.texture.sampler = d3d11->sampler_linear; else - d3d11->frame.sampler = d3d11->sampler_nearest; + d3d11->frame.texture.sampler = d3d11->sampler_nearest; } static void d3d11_gfx_set_rotation(void* data, unsigned rotation) @@ -467,9 +467,6 @@ static bool d3d11_gfx_frame( d3d11_update_texture( d3d11->ctx, width, height, pitch, d3d11->format, frame, &d3d11->frame.texture); - D3D11CopyTexture2DSubresourceRegion( - d3d11->ctx, d3d11->frame.texture.handle, 0, 0, 0, 0, d3d11->frame.texture.staging, 0, - &frame_box); } { @@ -482,8 +479,7 @@ static bool d3d11_gfx_frame( d3d11_update_viewport(d3d11, false); D3D11SetViewports(d3d11->ctx, 1, &d3d11->frame.viewport); - D3D11SetPShaderResources(d3d11->ctx, 0, 1, &d3d11->frame.texture.view); - D3D11SetPShaderSamplers(d3d11->ctx, 0, 1, &d3d11->frame.sampler); + d3d11_set_texture_and_sampler(d3d11->ctx, 0, &d3d11->frame.texture); D3D11SetVertexBuffers(d3d11->ctx, 0, 1, &d3d11->frame.vbo, &stride, &offset); D3D11SetVShaderConstantBuffers(d3d11->ctx, 0, 1, &d3d11->frame.ubo); @@ -493,20 +489,11 @@ static bool d3d11_gfx_frame( if (d3d11->menu.enabled && d3d11->menu.texture.handle) { - if (d3d11->menu.texture.dirty) - { - D3D11CopyTexture2DSubresourceRegion( - d3d11->ctx, d3d11->menu.texture.handle, 0, 0, 0, 0, d3d11->menu.texture.staging, - 0, NULL); - d3d11->menu.texture.dirty = false; - } - if (d3d11->menu.fullscreen) D3D11SetViewports(d3d11->ctx, 1, &d3d11->viewport); D3D11SetVertexBuffers(d3d11->ctx, 0, 1, &d3d11->menu.vbo, &stride, &offset); D3D11SetVShaderConstantBuffers(d3d11->ctx, 0, 1, &d3d11->ubo); - D3D11SetPShaderResources(d3d11->ctx, 0, 1, &d3d11->menu.texture.view); - D3D11SetPShaderSamplers(d3d11->ctx, 0, 1, &d3d11->menu.sampler); + d3d11_set_texture_and_sampler(d3d11->ctx, 0, &d3d11->menu.texture); D3D11Draw(d3d11->ctx, 4, 0); } @@ -521,7 +508,6 @@ static bool d3d11_gfx_frame( D3D11SetInputLayout(d3d11->ctx, d3d11->sprites.layout); D3D11SetPrimitiveTopology(d3d11->ctx, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); D3D11SetVertexBuffers(d3d11->ctx, 0, 1, &d3d11->sprites.vbo, &sprite_stride, &offset); - D3D11SetPShaderSamplers(d3d11->ctx, 0, 1, &d3d11->sampler_linear); D3D11SetBlendState(d3d11->ctx, d3d11->blend_enable, NULL, D3D11_DEFAULT_SAMPLE_MASK); d3d11->sprites.enabled = true; @@ -621,7 +607,7 @@ static void d3d11_set_menu_texture_frame( } d3d11_update_texture(d3d11->ctx, width, height, pitch, format, frame, &d3d11->menu.texture); - d3d11->menu.sampler = config_get_ptr()->bools.menu_linear_filter ? d3d11->sampler_linear + d3d11->menu.texture.sampler = config_get_ptr()->bools.menu_linear_filter ? d3d11->sampler_linear : d3d11->sampler_nearest; } static void d3d11_set_menu_texture_enable(void* data, bool state, bool full_screen) @@ -672,15 +658,30 @@ static uintptr_t d3d11_gfx_load_texture( { d3d11_video_t* d3d11 = (d3d11_video_t*)video_data; struct texture_image* image = (struct texture_image*)data; - D3D11_BOX frame_box = { 0, 0, 0, image->width, image->height, 1 }; if (!d3d11) return 0; d3d11_texture_t* texture = calloc(1, sizeof(*texture)); - texture->desc.Width = image->width; - texture->desc.Height = image->height; + switch(filter_type) + { + case TEXTURE_FILTER_MIPMAP_LINEAR: + texture->desc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS; + /* fallthrough */ + case TEXTURE_FILTER_LINEAR: + texture->sampler = d3d11->sampler_linear; + break; + case TEXTURE_FILTER_MIPMAP_NEAREST: + texture->desc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS; + /* fallthrough */ + case TEXTURE_FILTER_NEAREST: + texture->sampler = d3d11->sampler_nearest; + break; + } + + texture->desc.Width = image->width; + texture->desc.Height = image->height; texture->desc.Format = d3d11_get_closest_match_texture2D(d3d11->device, DXGI_FORMAT_B8G8R8A8_UNORM); @@ -689,8 +690,6 @@ static uintptr_t d3d11_gfx_load_texture( d3d11_update_texture( d3d11->ctx, image->width, image->height, 0, DXGI_FORMAT_B8G8R8A8_UNORM, image->pixels, texture); - D3D11CopyTexture2DSubresourceRegion( - d3d11->ctx, texture->handle, 0, 0, 0, 0, texture->staging, 0, &frame_box); return (uintptr_t)texture; } diff --git a/gfx/drivers_font/d3d11_font.c b/gfx/drivers_font/d3d11_font.c index 25bfb7b7f0..2bfc3f9db1 100644 --- a/gfx/drivers_font/d3d11_font.c +++ b/gfx/drivers_font/d3d11_font.c @@ -52,6 +52,7 @@ d3d11_font_init_font(void* data, const char* font_path, float font_size, bool is } font->atlas = font->font_driver->get_atlas(font->font_data); + font->texture.sampler = d3d11->sampler_linear; font->texture.desc.Width = font->atlas->width; font->texture.desc.Height = font->atlas->height; font->texture.desc.Format = @@ -60,8 +61,7 @@ d3d11_font_init_font(void* data, const char* font_path, float font_size, bool is d3d11_update_texture( d3d11->ctx, font->atlas->width, font->atlas->height, font->atlas->width, DXGI_FORMAT_A8_UNORM, font->atlas->buffer, &font->texture); - font->texture.dirty = true; - font->atlas->dirty = false; + font->atlas->dirty = false; return font; } @@ -208,20 +208,11 @@ static void d3d11_font_render_line( d3d11_update_texture( d3d11->ctx, font->atlas->width, font->atlas->height, font->atlas->width, DXGI_FORMAT_A8_UNORM, font->atlas->buffer, &font->texture); - font->atlas->dirty = false; - font->texture.dirty = true; - } - - if (font->texture.dirty) - { - D3D11_BOX frame_box = { 0, 0, 0, font->atlas->width, font->atlas->height, 1 }; - D3D11CopyTexture2DSubresourceRegion( - d3d11->ctx, font->texture.handle, 0, 0, 0, 0, font->texture.staging, 0, &frame_box); - font->texture.dirty = false; + font->atlas->dirty = false; } D3D11SetPShader(d3d11->ctx, d3d11->sprites.ps_8bit, NULL, 0); - D3D11SetPShaderResources(d3d11->ctx, 0, 1, &font->texture.view); + d3d11_set_texture_and_sampler(d3d11->ctx, 0, &font->texture); D3D11Draw(d3d11->ctx, count, d3d11->sprites.offset); D3D11SetPShader(d3d11->ctx, d3d11->sprites.ps, NULL, 0); diff --git a/menu/drivers_display/menu_display_d3d11.c b/menu/drivers_display/menu_display_d3d11.c index 0616d2ee14..91102fa413 100644 --- a/menu/drivers_display/menu_display_d3d11.c +++ b/menu/drivers_display/menu_display_d3d11.c @@ -52,10 +52,9 @@ static void menu_display_d3d11_draw(void* data) if (!d3d11->sprites.enabled) return; - if(d3d11->sprites.offset + 1 > d3d11->sprites.capacity) + if (d3d11->sprites.offset + 1 > d3d11->sprites.capacity) d3d11->sprites.offset = 0; - D3D11_MAPPED_SUBRESOURCE mapped_vbo; D3D11MapBuffer(d3d11->ctx, d3d11->sprites.vbo, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mapped_vbo); d3d11_sprite_t* v = (d3d11_sprite_t*)mapped_vbo.pData + d3d11->sprites.offset; @@ -70,7 +69,7 @@ static void menu_display_d3d11_draw(void* data) v->coords.w = 1.0f; v->coords.h = 1.0f; - if(draw->scale_factor) + if (draw->scale_factor) v->params.scaling = draw->scale_factor; else v->params.scaling = 1.0f; @@ -93,8 +92,7 @@ static void menu_display_d3d11_draw(void* data) #if 0 D3D11SetPShader(d3d11->ctx, d3d11->sprites.ps, NULL, 0); #endif - D3D11SetPShaderResources(d3d11->ctx, 0, 1, &((d3d11_texture_t*)draw->texture)->view); - + d3d11_set_texture_and_sampler(d3d11->ctx, 0, (d3d11_texture_t*)draw->texture); D3D11Draw(d3d11->ctx, 1, d3d11->sprites.offset); d3d11->sprites.offset++; From 580c0184c25f323026cc105972114c072838de08 Mon Sep 17 00:00:00 2001 From: aliaspider Date: Thu, 25 Jan 2018 05:46:48 +0100 Subject: [PATCH 2/4] (D3D11) font driver: fix text colors. --- gfx/drivers_font/d3d11_font.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/drivers_font/d3d11_font.c b/gfx/drivers_font/d3d11_font.c index 2bfc3f9db1..0d49496485 100644 --- a/gfx/drivers_font/d3d11_font.c +++ b/gfx/drivers_font/d3d11_font.c @@ -299,7 +299,7 @@ static void d3d11_font_render_msg( g = FONT_COLOR_GET_GREEN(params->color); b = FONT_COLOR_GET_BLUE(params->color); alpha = FONT_COLOR_GET_ALPHA(params->color); - color = params->color; + color = DXGI_COLOR_RGBA(r, g, b, alpha); } else { From da3a90a025a34727b2bc21310c3c26305ded1795 Mon Sep 17 00:00:00 2001 From: aliaspider Date: Thu, 25 Jan 2018 05:47:19 +0100 Subject: [PATCH 3/4] (D3D11) misc. --- gfx/drivers/d3d11.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/gfx/drivers/d3d11.c b/gfx/drivers/d3d11.c index c5513a6bcf..426df3944f 100644 --- a/gfx/drivers/d3d11.c +++ b/gfx/drivers/d3d11.c @@ -63,10 +63,10 @@ static void d3d11_update_viewport(void* data, bool force_full) video_driver_update_viewport(&d3d11->vp, force_full, d3d11->keep_aspect); - d3d11->frame.viewport.TopLeftX = (float)d3d11->vp.x; - d3d11->frame.viewport.TopLeftY = (float)d3d11->vp.y; - d3d11->frame.viewport.Width = (float)d3d11->vp.width; - d3d11->frame.viewport.Height = (float)d3d11->vp.height; + d3d11->frame.viewport.TopLeftX = d3d11->vp.x; + d3d11->frame.viewport.TopLeftY = d3d11->vp.y; + d3d11->frame.viewport.Width = d3d11->vp.width; + d3d11->frame.viewport.Height = d3d11->vp.height; d3d11->frame.viewport.MaxDepth = 0.0f; d3d11->frame.viewport.MaxDepth = 1.0f; @@ -456,8 +456,6 @@ static bool d3d11_gfx_frame( if (frame && width && height) { - D3D11_BOX frame_box = { 0, 0, 0, width, height, 1 }; - if (d3d11->frame.texture.desc.Width != width || d3d11->frame.texture.desc.Height != height) { d3d11->frame.texture.desc.Width = width; From 17aa49004f093b83fe89b51268f4c2ab1f5c602c Mon Sep 17 00:00:00 2001 From: aliaspider Date: Thu, 25 Jan 2018 06:24:39 +0100 Subject: [PATCH 4/4] (D3D10/11/12) prevent some crashes on driver re-init. --- gfx/drivers/d3d10.c | 38 ++++++++++++++++++++++++++------------ gfx/drivers/d3d11.c | 6 ++++-- gfx/drivers/d3d12.c | 5 ++++- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/gfx/drivers/d3d10.c b/gfx/drivers/d3d10.c index 45d6386c98..ab1f7c5a37 100644 --- a/gfx/drivers/d3d10.c +++ b/gfx/drivers/d3d10.c @@ -41,7 +41,11 @@ static void d3d10_gfx_set_rotation(void* data, unsigned rotation) math_matrix_4x4* mvp; d3d10_video_t* d3d10 = (d3d10_video_t*)data; - d3d10->frame.rotation = 3 * rotation; + if(!d3d10) + return; + + d3d10->frame.rotation = rotation; + matrix_4x4_rotate_z(rot, d3d10->frame.rotation * (M_PI / 2.0f)); matrix_4x4_multiply(d3d10->mvp, rot, d3d10->mvp_no_rot); @@ -71,6 +75,8 @@ static void* d3d10_gfx_init(const video_info_t* video, const input_driver_t** input, void** input_data) { WNDCLASSEX wndclass = { 0 }; + MONITORINFOEX current_mon; + HMONITOR hm_to_use; settings_t* settings = config_get_ptr(); gfx_ctx_input_t inp = { input, input_data }; d3d10_video_t* d3d10 = (d3d10_video_t*)calloc(1, sizeof(*d3d10)); @@ -83,6 +89,16 @@ d3d10_gfx_init(const video_info_t* video, const input_driver_t** input, void** i wndclass.lpfnWndProc = WndProcD3D; win32_window_init(&wndclass, true, NULL); + win32_monitor_info(¤t_mon, &hm_to_use, &d3d10->cur_mon_id); + + d3d10->vp.full_width = video->width; + d3d10->vp.full_height = video->height; + + if (!d3d10->vp.full_width) + d3d10->vp.full_width = current_mon.rcMonitor.right - current_mon.rcMonitor.left; + if (!d3d10->vp.full_height) + d3d10->vp.full_height = current_mon.rcMonitor.bottom - current_mon.rcMonitor.top; + if (!win32_set_video_mode(d3d10, video->width, video->height, video->fullscreen)) { RARCH_ERR("[D3D10]: win32_set_video_mode failed.\n"); @@ -133,11 +149,18 @@ d3d10_gfx_init(const video_info_t* video, const input_driver_t** input, void** i } D3D10SetRenderTargets(d3d10->device, 1, &d3d10->renderTargetView, NULL); - d3d10->vp.full_width = video->width; - d3d10->vp.full_height = video->height; d3d10->viewport.Width = video->width; d3d10->viewport.Height = video->height; d3d10->resize_viewport = true; + d3d10->keep_aspect = video->force_aspect; + d3d10->vsync = video->vsync; + d3d10->format = video->rgb32 ? DXGI_FORMAT_B8G8R8X8_UNORM : DXGI_FORMAT_B5G6R5_UNORM; + + d3d10->frame.texture.desc.Format = + d3d10_get_closest_match_texture2D(d3d10->device, d3d10->format); + d3d10->frame.texture.desc.Usage = D3D10_USAGE_DEFAULT; + + d3d10->menu.texture.desc.Usage = D3D10_USAGE_DEFAULT; matrix_4x4_ortho(d3d10->mvp_no_rot, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f); @@ -173,15 +196,6 @@ d3d10_gfx_init(const video_info_t* video, const input_driver_t** input, void** i d3d10_set_filtering(d3d10, 0, video->smooth); - d3d10->keep_aspect = video->force_aspect; - d3d10->vsync = video->vsync; - d3d10->format = video->rgb32 ? DXGI_FORMAT_B8G8R8X8_UNORM : DXGI_FORMAT_B5G6R5_UNORM; - - d3d10->frame.texture.desc.Format = - d3d10_get_closest_match_texture2D(d3d10->device, d3d10->format); - d3d10->frame.texture.desc.Usage = D3D10_USAGE_DEFAULT; - d3d10->menu.texture.desc.Usage = D3D10_USAGE_DEFAULT; - { d3d10_vertex_t vertices[] = { { { 0.0f, 0.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, diff --git a/gfx/drivers/d3d11.c b/gfx/drivers/d3d11.c index 426df3944f..0e2db2f3c7 100644 --- a/gfx/drivers/d3d11.c +++ b/gfx/drivers/d3d11.c @@ -46,7 +46,10 @@ static void d3d11_gfx_set_rotation(void* data, unsigned rotation) math_matrix_4x4* mvp; d3d11_video_t* d3d11 = (d3d11_video_t*)data; - d3d11->frame.rotation = 3 * rotation; + if(!d3d11) + return; + + d3d11->frame.rotation = rotation; matrix_4x4_rotate_z(rot, d3d11->frame.rotation * (M_PI / 2.0f)); matrix_4x4_multiply(d3d11->mvp, rot, d3d11->mvp_no_rot); @@ -210,7 +213,6 @@ d3d11_gfx_init(const video_info_t* video, const input_driver_t** input, void** i d3d11_get_closest_match_texture2D(d3d11->device, d3d11->format); d3d11->frame.texture.desc.Usage = D3D11_USAGE_DEFAULT; - d3d11->menu.texture.desc.Format = DXGI_FORMAT_B4G4R4A4_UNORM; d3d11->menu.texture.desc.Usage = D3D11_USAGE_DEFAULT; matrix_4x4_ortho(d3d11->mvp_no_rot, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f); diff --git a/gfx/drivers/d3d12.c b/gfx/drivers/d3d12.c index 7c69238155..16dde9ce33 100644 --- a/gfx/drivers/d3d12.c +++ b/gfx/drivers/d3d12.c @@ -42,7 +42,10 @@ static void d3d12_gfx_set_rotation(void* data, unsigned rotation) D3D12_RANGE read_range = { 0, 0 }; d3d12_video_t* d3d12 = (d3d12_video_t*)data; - d3d12->frame.rotation = 3 * rotation; + if(!d3d12) + return; + + d3d12->frame.rotation = rotation; matrix_4x4_rotate_z(rot, d3d12->frame.rotation * (M_PI / 2.0f)); matrix_4x4_multiply(d3d12->mvp, rot, d3d12->mvp_no_rot);