diff --git a/src/xenia/gpu/d3d11/d3d11_graphics_driver.cc b/src/xenia/gpu/d3d11/d3d11_graphics_driver.cc index 503a07aa0..07dd7edb3 100644 --- a/src/xenia/gpu/d3d11/d3d11_graphics_driver.cc +++ b/src/xenia/gpu/d3d11/d3d11_graphics_driver.cc @@ -21,8 +21,10 @@ using namespace xe::gpu::xenos; D3D11GraphicsDriver::D3D11GraphicsDriver( - Memory* memory, ID3D11Device* device) : + Memory* memory, IDXGISwapChain* swap_chain, ID3D11Device* device) : GraphicsDriver(memory) { + swap_chain_ = swap_chain; + swap_chain_->AddRef(); device_ = device; device_->AddRef(); device_->GetImmediateContext(&context_); @@ -30,6 +32,8 @@ D3D11GraphicsDriver::D3D11GraphicsDriver( xe_zero_struct(&state_, sizeof(state_)); + xe_zero_struct(&render_targets_, sizeof(render_targets_)); + HRESULT hr; D3D11_BUFFER_DESC buffer_desc; xe_zero_struct(&buffer_desc, sizeof(buffer_desc)); @@ -45,15 +49,51 @@ D3D11GraphicsDriver::D3D11GraphicsDriver( buffer_desc.ByteWidth = (32) * sizeof(int); hr = device_->CreateBuffer( &buffer_desc, NULL, &state_.constant_buffers.loop_constants); + + //const char* shader_source = + // "" + // "[maxvertexcount(4)]\n" + // "void main(triange RectVert input[3], inout TriangleStream output) {" + // " output.Append(input[0]);" + // " output.Append(input[1]);" + // " output.Append(input[2]);" + // " /* compute 3 */" + // " output.RestartStrip();" + // "}"; + //ID3D10Blob* shader_blob = 0; + //ID3D10Blob* error_blob = 0; + //HRESULT hr = D3DCompile( + // shader_source, strlen(shader_source), + // "d3d11_rect_shader.gs", + // NULL, NULL, + // "main", + // "gs_5_0", + // D3D10_SHADER_DEBUG | D3D10_SHADER_ENABLE_STRICTNESS, 0, + // &shader_blob, &error_blob); + //if (error_blob) { + // char* msg = (char*)error_blob->GetBufferPointer(); + // XELOGE("D3D11: rect shader compile failed with %s", msg); + //} + //XESAFERELEASE(error_blob); + + //byte* rect_shader_bytes = 0; + //size_t rect_shader_length = 0; + //ID3D11GeometryShader* rect_shader; + //hr = device_->CreateGeometryShader( + // shader_blob->GetBufferPointer(), + // shader_blob->GetBufferSize(), + // NULL, &rect_shader); } D3D11GraphicsDriver::~D3D11GraphicsDriver() { + RebuildRenderTargets(0, 0); XESAFERELEASE(state_.constant_buffers.float_constants); XESAFERELEASE(state_.constant_buffers.bool_constants); XESAFERELEASE(state_.constant_buffers.loop_constants); delete shader_cache_; XESAFERELEASE(context_); XESAFERELEASE(device_); + XESAFERELEASE(swap_chain_); } void D3D11GraphicsDriver::Initialize() { @@ -209,16 +249,168 @@ void D3D11GraphicsDriver::DrawIndexAuto( context_->Draw(index_count, 0); } +int D3D11GraphicsDriver::RebuildRenderTargets( + uint32_t width, uint32_t height) { + if (width == render_targets_.width && + height == render_targets_.height) { + // Cached copies are good. + return 0; + } + + // Remove old versions. + for (int n = 0; n < XECOUNT(render_targets_.color_buffers); n++) { + auto& cb = render_targets_.color_buffers[n]; + XESAFERELEASE(cb.buffer); + XESAFERELEASE(cb.color_view_8888); + } + XESAFERELEASE(render_targets_.depth_buffer); + XESAFERELEASE(render_targets_.depth_view_d28s8); + XESAFERELEASE(render_targets_.depth_view_d28fs8); + + render_targets_.width = width; + render_targets_.height = height; + + if (!width || !height) { + // This should only happen when cleaning up. + return 0; + } + + for (int n = 0; n < XECOUNT(render_targets_.color_buffers); n++) { + auto& cb = render_targets_.color_buffers[n]; + D3D11_TEXTURE2D_DESC color_buffer_desc; + xe_zero_struct(&color_buffer_desc, sizeof(color_buffer_desc)); + color_buffer_desc.Width = width; + color_buffer_desc.Height = height; + color_buffer_desc.MipLevels = 1; + color_buffer_desc.ArraySize = 1; + color_buffer_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + color_buffer_desc.SampleDesc.Count = 1; + color_buffer_desc.SampleDesc.Quality = 0; + color_buffer_desc.Usage = D3D11_USAGE_DEFAULT; + color_buffer_desc.BindFlags = + D3D11_BIND_SHADER_RESOURCE | + D3D11_BIND_RENDER_TARGET; + color_buffer_desc.CPUAccessFlags = 0; + color_buffer_desc.MiscFlags = 0; + device_->CreateTexture2D( + &color_buffer_desc, NULL, &cb.buffer); + + D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc; + xe_zero_struct(&render_target_view_desc, sizeof(render_target_view_desc)); + render_target_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + // render_target_view_desc.Buffer ? + device_->CreateRenderTargetView( + cb.buffer, + &render_target_view_desc, + &cb.color_view_8888); + } + + D3D11_TEXTURE2D_DESC depth_stencil_desc; + xe_zero_struct(&depth_stencil_desc, sizeof(depth_stencil_desc)); + depth_stencil_desc.Width = width; + depth_stencil_desc.Height = height; + depth_stencil_desc.MipLevels = 1; + depth_stencil_desc.ArraySize = 1; + depth_stencil_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + depth_stencil_desc.SampleDesc.Count = 1; + depth_stencil_desc.SampleDesc.Quality = 0; + depth_stencil_desc.Usage = D3D11_USAGE_DEFAULT; + depth_stencil_desc.BindFlags = + D3D11_BIND_DEPTH_STENCIL; + depth_stencil_desc.CPUAccessFlags = 0; + depth_stencil_desc.MiscFlags = 0; + device_->CreateTexture2D( + &depth_stencil_desc, NULL, &render_targets_.depth_buffer); + + D3D11_DEPTH_STENCIL_VIEW_DESC depth_stencil_view_desc; + xe_zero_struct(&depth_stencil_view_desc, sizeof(depth_stencil_view_desc)); + depth_stencil_view_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + depth_stencil_view_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + depth_stencil_view_desc.Flags = 0; + device_->CreateDepthStencilView( + render_targets_.depth_buffer, + &depth_stencil_view_desc, + &render_targets_.depth_view_d28s8); + + return 0; +} + int D3D11GraphicsDriver::UpdateState() { + // Most information comes from here: // https://chromium.googlesource.com/chromiumos/third_party/mesa/+/6173cc19c45d92ef0b7bc6aa008aa89bb29abbda/src/gallium/drivers/freedreno/freedreno_zsa.c // http://cgit.freedesktop.org/mesa/mesa/diff/?id=aac7f06ad843eaa696363e8e9c7781ca30cb4914 + // The only differences so far are extra packets for multiple render targets + // and a few modes being switched around. + RegisterFile& rf = register_file_; - // RB_SURFACE_INFO - // RB_DEPTH_INFO + uint32_t window_scissor_tl = rf.values[XE_GPU_REG_PA_SC_WINDOW_SCISSOR_TL].u32; + uint32_t window_scissor_br = rf.values[XE_GPU_REG_PA_SC_WINDOW_SCISSOR_BR].u32; + //uint32_t window_width = + // (window_scissor_br & 0xFFFF) - (window_scissor_tl & 0xFFFF); + //uint32_t window_height = + // (window_scissor_br >> 16) - (window_scissor_tl >> 16); + uint32_t window_width = 1280; + uint32_t window_height = 720; + if (RebuildRenderTargets(window_width, window_height)) { + XELOGE("Unable to rebuild render targets to %d x %d", + window_width, window_height); + return 1; + } + + // RB_SURFACE_INFO ? + + // Enable buffers. + uint32_t enable_mode = rf.values[XE_GPU_REG_RB_MODECONTROL].u32 & 0x7; + // 4 = color + depth + // 6 = copy ? + + // color_info[0-3] has format 8888 + uint32_t color_info[4] = { + rf.values[XE_GPU_REG_RB_COLOR_INFO].u32, + rf.values[XE_GPU_REG_RB_COLOR1_INFO].u32, + rf.values[XE_GPU_REG_RB_COLOR2_INFO].u32, + rf.values[XE_GPU_REG_RB_COLOR3_INFO].u32, + }; + ID3D11RenderTargetView* render_target_views[4] = { 0 }; + for (int n = 0; n < XECOUNT(color_info); n++) { + auto cb = render_targets_.color_buffers[n]; + uint32_t color_format = (color_info[n] >> 16) & 0xF; + switch (color_format) { + case 0: // D3DFMT_A8R8G8B8 (or ABGR?) + case 1: + render_target_views[n] = cb.color_view_8888; + break; + default: + // Unknown. + XELOGGPU("Unsupported render target format %d", color_format); + break; + } + } + + // depth_info has format 24_8 + uint32_t depth_info = rf.values[XE_GPU_REG_RB_DEPTH_INFO].u32; + uint32_t depth_format = (depth_info >> 16) & 0x1; + ID3D11DepthStencilView* depth_stencil_view = 0; + switch (depth_format) { + case 0: // D3DFMT_D24S8 + depth_stencil_view = render_targets_.depth_view_d28s8; + break; + default: + case 1: // D3DFMT_D24FS8 + //depth_stencil_view = render_targets_.depth_view_d28fs8; + XELOGGPU("Unsupported depth/stencil format %d", depth_format); + break; + } + // TODO(benvanik): when a game switches does it expect to keep the same + // depth buffer contents? + + // TODO(benvanik): only enable the number of valid render targets. + context_->OMSetRenderTargets(4, render_target_views, depth_stencil_view); // General rasterizer state. - uint32_t mode_control = rf.values[XE_GPU_REG_RB_MODECONTROL].u32; + uint32_t mode_control = rf.values[XE_GPU_REG_PA_SU_SC_MODE_CNTL].u32; D3D11_RASTERIZER_DESC rasterizer_desc; xe_zero_struct(&rasterizer_desc, sizeof(rasterizer_desc)); rasterizer_desc.FillMode = D3D11_FILL_SOLID; // D3D11_FILL_WIREFRAME; @@ -246,64 +438,10 @@ int D3D11GraphicsDriver::UpdateState() { context_->RSSetState(rasterizer_state); XESAFERELEASE(rasterizer_state); - // Depth-stencil state. - uint32_t depth_control = rf.values[XE_GPU_REG_RB_DEPTHCONTROL].u32; - D3D11_DEPTH_STENCIL_DESC depth_stencil_desc; - xe_zero_struct(&depth_stencil_desc, sizeof(depth_stencil_desc)); - // A2XX_RB_DEPTHCONTROL_BACKFACE_ENABLE - // ? - // A2XX_RB_DEPTHCONTROL_Z_ENABLE - depth_stencil_desc.DepthEnable = (depth_control & 0x00000002) != 0; - // A2XX_RB_DEPTHCONTROL_Z_WRITE_ENABLE - depth_stencil_desc.DepthWriteMask = (depth_control & 0x00000004) ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; - // A2XX_RB_DEPTHCONTROL_EARLY_Z_ENABLE - // ? - // A2XX_RB_DEPTHCONTROL_ZFUNC - // 0 = never, 7 = always -- almost lines up - depth_stencil_desc.DepthFunc = (D3D11_COMPARISON_FUNC)(((depth_control & 0x00000070) >> 4) + 1); - // A2XX_RB_DEPTHCONTROL_STENCIL_ENABLE - depth_stencil_desc.StencilEnable = (depth_control & 0x00000001) != 0; - depth_stencil_desc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - depth_stencil_desc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - // A2XX_RB_DEPTHCONTROL_STENCILFUNC - depth_stencil_desc.FrontFace.StencilFunc = - (D3D11_COMPARISON_FUNC)(((depth_control & 0x00000700) >> 8) + 1); - // A2XX_RB_DEPTHCONTROL_STENCILFAIL - // 0 = keep, 7 = decr -- almost lines up - depth_stencil_desc.FrontFace.StencilFailOp = - (D3D11_STENCIL_OP)(((depth_control & 0x00003800) >> 11) + 1); - // A2XX_RB_DEPTHCONTROL_STENCILZPASS - depth_stencil_desc.FrontFace.StencilPassOp = - (D3D11_STENCIL_OP)(((depth_control & 0x0001C000) >> 14) + 1); - // A2XX_RB_DEPTHCONTROL_STENCILZFAIL - depth_stencil_desc.FrontFace.StencilDepthFailOp = - (D3D11_STENCIL_OP)(((depth_control & 0x000E0000) >> 17) + 1); - // A2XX_RB_DEPTHCONTROL_STENCILFUNC_BF - depth_stencil_desc.BackFace.StencilFunc = - (D3D11_COMPARISON_FUNC)(((depth_control & 0x00700000) >> 20) + 1); - // A2XX_RB_DEPTHCONTROL_STENCILFAIL_BF - depth_stencil_desc.BackFace.StencilFailOp = - (D3D11_STENCIL_OP)(((depth_control & 0x03800000) >> 23) + 1); - // A2XX_RB_DEPTHCONTROL_STENCILZPASS_BF - depth_stencil_desc.BackFace.StencilPassOp = - (D3D11_STENCIL_OP)(((depth_control & 0x1C000000) >> 26) + 1); - // A2XX_RB_DEPTHCONTROL_STENCILZFAIL_BF - depth_stencil_desc.BackFace.StencilDepthFailOp = - (D3D11_STENCIL_OP)(((depth_control & 0xE0000000) >> 29) + 1); - ID3D11DepthStencilState* depth_stencil_state = 0; - device_->CreateDepthStencilState(&depth_stencil_desc, &depth_stencil_state); - context_->OMSetDepthStencilState(depth_stencil_state, 0 /* stencil ref */); - XESAFERELEASE(depth_stencil_state); - - // Blend state. - //context_->OMSetBlendState(blend_state, blend_factor, sample_mask); - - // Scissoring. - // TODO(benvanik): pull from scissor registers. - context_->RSSetScissorRects(0, NULL); - // Viewport. // If we have resized the window we will want to change this. + uint32_t window_offset = rf.values[XE_GPU_REG_PA_SC_WINDOW_OFFSET].u32; + // ? D3D11_VIEWPORT viewport; viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; @@ -313,6 +451,179 @@ int D3D11GraphicsDriver::UpdateState() { viewport.Height = 720; context_->RSSetViewports(1, &viewport); + // ? + // TODO(benvanik): figure out how to emulate viewports in D3D11. Could use + // viewport above to scale, though that doesn't support negatives/etc. + float vport_xoffset = rf.values[XE_GPU_REG_PA_CL_VPORT_XOFFSET].f32; // 640 + float vport_xscale = rf.values[XE_GPU_REG_PA_CL_VPORT_XSCALE].f32; // 640 + float vport_yoffset = rf.values[XE_GPU_REG_PA_CL_VPORT_YOFFSET].f32; // 360 + float vport_yscale = rf.values[XE_GPU_REG_PA_CL_VPORT_YSCALE].f32; // -360 + float vport_zoffset = rf.values[XE_GPU_REG_PA_CL_VPORT_ZOFFSET].f32; // 0 + float vport_zscale = rf.values[XE_GPU_REG_PA_CL_VPORT_ZSCALE].f32; // 1 + + // Scissoring. + // TODO(benvanik): pull from scissor registers. + // ScissorEnable must be set in raster state above. + uint32_t screen_scissor_tl = rf.values[XE_GPU_REG_PA_SC_SCREEN_SCISSOR_TL].u32; + uint32_t screen_scissor_br = rf.values[XE_GPU_REG_PA_SC_SCREEN_SCISSOR_BR].u32; + if (screen_scissor_tl != 0 && screen_scissor_br != 0x20002000) { + D3D11_RECT scissor_rect; + scissor_rect.top = screen_scissor_tl >> 16; + scissor_rect.left = screen_scissor_tl & 0xFFFF; + scissor_rect.bottom = screen_scissor_br >> 16; + scissor_rect.right = screen_scissor_br & 0xFFFF; + context_->RSSetScissorRects(1, &scissor_rect); + } else { + context_->RSSetScissorRects(0, NULL); + } + + static const D3D11_COMPARISON_FUNC compare_func_map[] = { + /* 0 */ D3D11_COMPARISON_NEVER, + /* 1 */ D3D11_COMPARISON_LESS, + /* 2 */ D3D11_COMPARISON_EQUAL, + /* 3 */ D3D11_COMPARISON_LESS_EQUAL, + /* 4 */ D3D11_COMPARISON_GREATER, + /* 5 */ D3D11_COMPARISON_NOT_EQUAL, + /* 6 */ D3D11_COMPARISON_GREATER_EQUAL, + /* 7 */ D3D11_COMPARISON_ALWAYS, + }; + static const D3D11_STENCIL_OP stencil_op_map[] = { + /* 0 */ D3D11_STENCIL_OP_KEEP, + /* 1 */ D3D11_STENCIL_OP_ZERO, + /* 2 */ D3D11_STENCIL_OP_REPLACE, + /* 3 */ D3D11_STENCIL_OP_INCR_SAT, + /* 4 */ D3D11_STENCIL_OP_DECR_SAT, + /* 5 */ D3D11_STENCIL_OP_INVERT, + /* 6 */ D3D11_STENCIL_OP_INCR, + /* 7 */ D3D11_STENCIL_OP_DECR, + }; + + // Depth-stencil state. + uint32_t depth_control = rf.values[XE_GPU_REG_RB_DEPTHCONTROL].u32; + uint32_t stencil_ref_mask = rf.values[XE_GPU_REG_RB_STENCILREFMASK].u32; + D3D11_DEPTH_STENCIL_DESC depth_stencil_desc; + xe_zero_struct(&depth_stencil_desc, sizeof(depth_stencil_desc)); + // A2XX_RB_DEPTHCONTROL_BACKFACE_ENABLE + // ? + // A2XX_RB_DEPTHCONTROL_Z_ENABLE + depth_stencil_desc.DepthEnable = (depth_control & 0x00000002) != 0; + // A2XX_RB_DEPTHCONTROL_Z_WRITE_ENABLE + depth_stencil_desc.DepthWriteMask = (depth_control & 0x00000004) ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + // A2XX_RB_DEPTHCONTROL_EARLY_Z_ENABLE + // ? + // A2XX_RB_DEPTHCONTROL_ZFUNC + depth_stencil_desc.DepthFunc = compare_func_map[(depth_control & 0x00000070) >> 4]; + // A2XX_RB_DEPTHCONTROL_STENCIL_ENABLE + depth_stencil_desc.StencilEnable = (depth_control & 0x00000001) != 0; + // RB_STENCILREFMASK_STENCILMASK + depth_stencil_desc.StencilReadMask = (stencil_ref_mask & 0x0000FF00) >> 8; + // RB_STENCILREFMASK_STENCILWRITEMASK + depth_stencil_desc.StencilWriteMask = (stencil_ref_mask & 0x00FF0000) >> 16; + // A2XX_RB_DEPTHCONTROL_STENCILFUNC + depth_stencil_desc.FrontFace.StencilFunc = compare_func_map[(depth_control & 0x00000700) >> 8]; + // A2XX_RB_DEPTHCONTROL_STENCILFAIL + depth_stencil_desc.FrontFace.StencilFailOp = stencil_op_map[(depth_control & 0x00003800) >> 11]; + // A2XX_RB_DEPTHCONTROL_STENCILZPASS + depth_stencil_desc.FrontFace.StencilPassOp = stencil_op_map[(depth_control & 0x0001C000) >> 14]; + // A2XX_RB_DEPTHCONTROL_STENCILZFAIL + depth_stencil_desc.FrontFace.StencilDepthFailOp = stencil_op_map[(depth_control & 0x000E0000) >> 17]; + // A2XX_RB_DEPTHCONTROL_STENCILFUNC_BF + depth_stencil_desc.BackFace.StencilFunc = compare_func_map[(depth_control & 0x00700000) >> 20]; + // A2XX_RB_DEPTHCONTROL_STENCILFAIL_BF + depth_stencil_desc.BackFace.StencilFailOp = stencil_op_map[(depth_control & 0x03800000) >> 23]; + // A2XX_RB_DEPTHCONTROL_STENCILZPASS_BF + depth_stencil_desc.BackFace.StencilPassOp = stencil_op_map[(depth_control & 0x1C000000) >> 26]; + // A2XX_RB_DEPTHCONTROL_STENCILZFAIL_BF + depth_stencil_desc.BackFace.StencilDepthFailOp = stencil_op_map[(depth_control & 0xE0000000) >> 29]; + // RB_STENCILREFMASK_STENCILREF + uint32_t stencil_ref = (stencil_ref_mask & 0x000000FF); + ID3D11DepthStencilState* depth_stencil_state = 0; + device_->CreateDepthStencilState(&depth_stencil_desc, &depth_stencil_state); + context_->OMSetDepthStencilState(depth_stencil_state, stencil_ref); + XESAFERELEASE(depth_stencil_state); + + static const D3D11_BLEND blend_map[] = { + /* 0 */ D3D11_BLEND_ZERO, + /* 1 */ D3D11_BLEND_ONE, + /* 2 */ D3D11_BLEND_ZERO, // ? + /* 3 */ D3D11_BLEND_ZERO, // ? + /* 4 */ D3D11_BLEND_SRC_COLOR, + /* 5 */ D3D11_BLEND_INV_SRC_COLOR, + /* 6 */ D3D11_BLEND_SRC_ALPHA, + /* 7 */ D3D11_BLEND_INV_SRC_ALPHA, + /* 8 */ D3D11_BLEND_DEST_COLOR, + /* 9 */ D3D11_BLEND_INV_DEST_COLOR, + /* 10 */ D3D11_BLEND_DEST_ALPHA, + /* 11 */ D3D11_BLEND_INV_DEST_ALPHA, + /* 12 */ D3D11_BLEND_BLEND_FACTOR, + /* 13 */ D3D11_BLEND_INV_BLEND_FACTOR, + /* 14 */ D3D11_BLEND_SRC1_ALPHA, // ? + /* 15 */ D3D11_BLEND_INV_SRC1_ALPHA, // ? + /* 16 */ D3D11_BLEND_SRC_ALPHA_SAT, + }; + static const D3D11_BLEND_OP blend_op_map[] = { + /* 0 */ D3D11_BLEND_OP_ADD, + /* 1 */ D3D11_BLEND_OP_SUBTRACT, + /* 2 */ D3D11_BLEND_OP_MIN, + /* 3 */ D3D11_BLEND_OP_MAX, + /* 4 */ D3D11_BLEND_OP_REV_SUBTRACT, + }; + + // alpha testing -- ALPHAREF, ALPHAFUNC, ALPHATESTENABLE + // Not in D3D11! + // http://msdn.microsoft.com/en-us/library/windows/desktop/bb205120(v=vs.85).aspx + uint32_t color_control = rf.values[XE_GPU_REG_RB_COLORCONTROL].u32; + + // Blend state. + uint32_t color_mask = rf.values[XE_GPU_REG_RB_COLOR_MASK].u32; + uint32_t sample_mask = 0xFFFFFFFF; // ? + float blend_factor[4] = { + rf.values[XE_GPU_REG_RB_BLEND_RED].f32, + rf.values[XE_GPU_REG_RB_BLEND_GREEN].f32, + rf.values[XE_GPU_REG_RB_BLEND_BLUE].f32, + rf.values[XE_GPU_REG_RB_BLEND_ALPHA].f32, + }; + uint32_t blend_control[4] = { + rf.values[XE_GPU_REG_RB_BLENDCONTROL_0].u32, + rf.values[XE_GPU_REG_RB_BLENDCONTROL_1].u32, + rf.values[XE_GPU_REG_RB_BLENDCONTROL_2].u32, + rf.values[XE_GPU_REG_RB_BLENDCONTROL_3].u32, + }; + D3D11_BLEND_DESC blend_desc; + xe_zero_struct(&blend_desc, sizeof(blend_desc)); + //blend_desc.AlphaToCoverageEnable = false; + // ? + blend_desc.IndependentBlendEnable = true; + for (int n = 0; n < XECOUNT(blend_control); n++) { + // A2XX_RB_BLEND_CONTROL_COLOR_SRCBLEND + blend_desc.RenderTarget[n].SrcBlend = blend_map[(blend_control[n] & 0x0000001F) >> 0]; + // A2XX_RB_BLEND_CONTROL_COLOR_DESTBLEND + blend_desc.RenderTarget[n].DestBlend = blend_map[(blend_control[n] & 0x00001F00) >> 8]; + // A2XX_RB_BLEND_CONTROL_COLOR_COMB_FCN + blend_desc.RenderTarget[n].BlendOp = blend_op_map[(blend_control[n] & 0x000000E0) >> 5]; + // A2XX_RB_BLEND_CONTROL_ALPHA_SRCBLEND + blend_desc.RenderTarget[n].SrcBlendAlpha = blend_map[(blend_control[n] & 0x001F0000) >> 16]; + // A2XX_RB_BLEND_CONTROL_ALPHA_DESTBLEND + blend_desc.RenderTarget[n].DestBlendAlpha = blend_map[(blend_control[n] & 0x1F000000) >> 24]; + // A2XX_RB_BLEND_CONTROL_ALPHA_COMB_FCN + blend_desc.RenderTarget[n].BlendOpAlpha = blend_op_map[(blend_control[n] & 0x00E00000) >> 21]; + // A2XX_RB_COLOR_MASK_WRITE_* + blend_desc.RenderTarget[n].RenderTargetWriteMask = (color_mask >> (n * 4)) & 0xF; + // A2XX_RB_COLORCONTROL_BLEND_DISABLE ?? Can't find this! + // Just guess based on actions. + blend_desc.RenderTarget[n].BlendEnable = !( + (blend_desc.RenderTarget[n].SrcBlend == D3D11_BLEND_ONE) && + (blend_desc.RenderTarget[n].DestBlend == D3D11_BLEND_ZERO) && + (blend_desc.RenderTarget[n].BlendOp == D3D11_BLEND_OP_ADD) && + (blend_desc.RenderTarget[n].SrcBlendAlpha == D3D11_BLEND_ONE) && + (blend_desc.RenderTarget[n].DestBlendAlpha == D3D11_BLEND_ZERO) && + (blend_desc.RenderTarget[n].BlendOpAlpha == D3D11_BLEND_OP_ADD)); + } + ID3D11BlendState* blend_state = 0; + device_->CreateBlendState(&blend_desc, &blend_state); + context_->OMSetBlendState(blend_state, blend_factor, sample_mask); + XESAFERELEASE(blend_state); + return 0; } @@ -590,3 +901,30 @@ int D3D11GraphicsDriver::PrepareIndexBuffer( return 0; } + +int D3D11GraphicsDriver::Resolve() { + // No clue how this is supposed to work yet. + ID3D11Texture2D* back_buffer = 0; + swap_chain_->GetBuffer(0, __uuidof(ID3D11Texture2D), + (LPVOID*)&back_buffer); + D3D11_TEXTURE2D_DESC desc; + back_buffer->GetDesc(&desc); + if (desc.Width == render_targets_.width && + desc.Height == render_targets_.height) { + // Same size/format, so copy quickly. + context_->CopyResource(back_buffer, render_targets_.color_buffers[0].buffer); + } else { + // TODO(benvanik): scale size using a quad draw. + } + XESAFERELEASE(back_buffer); + + // TODO(benvanik): remove! + float color[4] = { 0.5f, 0.5f, 0.0f, 1.0f }; + context_->ClearRenderTargetView( + render_targets_.color_buffers[0].color_view_8888, color); + // TODO(benvanik): take clear values from register + context_->ClearDepthStencilView( + render_targets_.depth_view_d28s8, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1, 0); + + return 0; +} diff --git a/src/xenia/gpu/d3d11/d3d11_graphics_driver.h b/src/xenia/gpu/d3d11/d3d11_graphics_driver.h index 75db4e7b0..91d96eb19 100644 --- a/src/xenia/gpu/d3d11/d3d11_graphics_driver.h +++ b/src/xenia/gpu/d3d11/d3d11_graphics_driver.h @@ -31,7 +31,8 @@ class D3D11VertexShader; class D3D11GraphicsDriver : public GraphicsDriver { public: - D3D11GraphicsDriver(Memory* memory, ID3D11Device* device); + D3D11GraphicsDriver( + Memory* memory, IDXGISwapChain* swap_chain, ID3D11Device* device); virtual ~D3D11GraphicsDriver(); virtual void Initialize(); @@ -51,8 +52,12 @@ public: xenos::XE_GPU_PRIMITIVE_TYPE prim_type, uint32_t index_count); + // TODO(benvanik): figure this out. + virtual int Resolve(); + private: int SetupDraw(xenos::XE_GPU_PRIMITIVE_TYPE prim_type); + int RebuildRenderTargets(uint32_t width, uint32_t height); int UpdateState(); int UpdateConstantBuffers(); int BindShaders(); @@ -65,10 +70,23 @@ private: uint32_t index_base, uint32_t index_size, uint32_t endianness); private: + IDXGISwapChain* swap_chain_; ID3D11Device* device_; ID3D11DeviceContext* context_; D3D11ShaderCache* shader_cache_; + struct { + uint32_t width; + uint32_t height; + struct { + ID3D11Texture2D* buffer; + ID3D11RenderTargetView* color_view_8888; + } color_buffers[4]; + ID3D11Texture2D* depth_buffer; + ID3D11DepthStencilView* depth_view_d28s8; + ID3D11DepthStencilView* depth_view_d28fs8; + } render_targets_; + struct { D3D11VertexShader* vertex_shader; D3D11PixelShader* pixel_shader; diff --git a/src/xenia/gpu/d3d11/d3d11_graphics_system.cc b/src/xenia/gpu/d3d11/d3d11_graphics_system.cc index a0965fc7e..f1432dc50 100644 --- a/src/xenia/gpu/d3d11/d3d11_graphics_system.cc +++ b/src/xenia/gpu/d3d11/d3d11_graphics_system.cc @@ -137,7 +137,8 @@ void D3D11GraphicsSystem::Initialize() { // This runs in the worker thread and builds command lines to present // in the window. XEASSERTNULL(driver_); - driver_ = new D3D11GraphicsDriver(memory_, device_); + driver_ = new D3D11GraphicsDriver( + memory_, window_->swap_chain(), device_); // Initial vsync kick. DispatchInterruptCallback(0); @@ -147,6 +148,9 @@ void D3D11GraphicsSystem::Pump() { if (swap_pending_) { swap_pending_ = false; + // TODO(benvanik): remove this when commands are understood. + driver_->Resolve(); + // Swap window. // If we are set to vsync this will block. window_->Swap(); diff --git a/src/xenia/gpu/d3d11/d3d11_window.cc b/src/xenia/gpu/d3d11/d3d11_window.cc index 1723b6d6e..930149694 100644 --- a/src/xenia/gpu/d3d11/d3d11_window.cc +++ b/src/xenia/gpu/d3d11/d3d11_window.cc @@ -57,11 +57,11 @@ int D3D11Window::Initialize(const char* title, uint32_t width, uint32_t height) xe_zero_struct(&desc, sizeof(desc)); desc.OutputWindow = handle(); desc.Windowed = TRUE; - desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // Setup buffers. - desc.BufferCount = 1; + desc.BufferCount = 2; desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; desc.BufferDesc.Width = width; desc.BufferDesc.Height = height; diff --git a/src/xenia/gpu/d3d11/d3d11_window.h b/src/xenia/gpu/d3d11/d3d11_window.h index 51a2a6c8e..f9e47723d 100644 --- a/src/xenia/gpu/d3d11/d3d11_window.h +++ b/src/xenia/gpu/d3d11/d3d11_window.h @@ -29,6 +29,8 @@ public: IDXGIFactory1* dxgi_factory, ID3D11Device* device); virtual ~D3D11Window(); + IDXGISwapChain* swap_chain() const { return swap_chain_; } + virtual int Initialize(const char* title, uint32_t width, uint32_t height); void Swap(); diff --git a/src/xenia/gpu/graphics_driver.h b/src/xenia/gpu/graphics_driver.h index 157d9edf4..675a5a7c2 100644 --- a/src/xenia/gpu/graphics_driver.h +++ b/src/xenia/gpu/graphics_driver.h @@ -47,6 +47,8 @@ public: xenos::XE_GPU_PRIMITIVE_TYPE prim_type, uint32_t index_count) = 0; + virtual int Resolve() = 0; + protected: GraphicsDriver(Memory* memory); diff --git a/src/xenia/gpu/nop/nop_graphics_driver.cc b/src/xenia/gpu/nop/nop_graphics_driver.cc index 7bd255845..69f88fa95 100644 --- a/src/xenia/gpu/nop/nop_graphics_driver.cc +++ b/src/xenia/gpu/nop/nop_graphics_driver.cc @@ -83,3 +83,7 @@ void NopGraphicsDriver::DrawIndexAuto( // shader constants / bools / integers // fetch constants } + +int NopGraphicsDriver::Resolve() { + return 0; +} diff --git a/src/xenia/gpu/nop/nop_graphics_driver.h b/src/xenia/gpu/nop/nop_graphics_driver.h index f01a9636a..d345c8159 100644 --- a/src/xenia/gpu/nop/nop_graphics_driver.h +++ b/src/xenia/gpu/nop/nop_graphics_driver.h @@ -47,6 +47,8 @@ public: xenos::XE_GPU_PRIMITIVE_TYPE prim_type, uint32_t index_count); + virtual int Resolve(); + protected: ShaderCache* shader_cache_; }; diff --git a/src/xenia/kernel/xboxkrnl_debug.cc b/src/xenia/kernel/xboxkrnl_debug.cc index 05c5c99f4..5b709cbb5 100644 --- a/src/xenia/kernel/xboxkrnl_debug.cc +++ b/src/xenia/kernel/xboxkrnl_debug.cc @@ -203,7 +203,7 @@ SHIM_CALL DbgPrint_shim( uint32_t value = arg_index < 7 ? SHIM_GET_ARG_32(1 + arg_index) : (uint32_t)SHIM_MEM_64(SHIM_GPR_32(1) + 16 + ((1 + arg_index) * 8)); - SHIM_SET_MEM_32(value, (b - buffer) / sizeof(char)); + SHIM_SET_MEM_32(value, (uint32_t)((b - buffer) / sizeof(char))); arg_index++; } else {