diff options
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 13 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 104 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.h | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/maxwell_to_gl.h | 66 | ||||
| -rw-r--r-- | src/video_core/textures/texture.h | 13 |
9 files changed, 138 insertions, 88 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 5ae836aca..d1777b25b 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -53,6 +53,19 @@ void Maxwell3D::InitializeRegisterDefaults() { | |||
| 53 | regs.independent_blend[blend_index].factor_source_a = Regs::Blend::Factor::One; | 53 | regs.independent_blend[blend_index].factor_source_a = Regs::Blend::Factor::One; |
| 54 | regs.independent_blend[blend_index].factor_dest_a = Regs::Blend::Factor::Zero; | 54 | regs.independent_blend[blend_index].factor_dest_a = Regs::Blend::Factor::Zero; |
| 55 | } | 55 | } |
| 56 | regs.stencil_front_op_fail = Regs::StencilOp::Keep; | ||
| 57 | regs.stencil_front_op_zfail = Regs::StencilOp::Keep; | ||
| 58 | regs.stencil_front_op_zpass = Regs::StencilOp::Keep; | ||
| 59 | regs.stencil_front_func_func = Regs::ComparisonOp::Always; | ||
| 60 | regs.stencil_front_func_mask = 0xFFFFFFFF; | ||
| 61 | regs.stencil_front_mask = 0xFFFFFFFF; | ||
| 62 | regs.stencil_two_side_enable = 1; | ||
| 63 | regs.stencil_back_op_fail = Regs::StencilOp::Keep; | ||
| 64 | regs.stencil_back_op_zfail = Regs::StencilOp::Keep; | ||
| 65 | regs.stencil_back_op_zpass = Regs::StencilOp::Keep; | ||
| 66 | regs.stencil_back_func_func = Regs::ComparisonOp::Always; | ||
| 67 | regs.stencil_back_func_mask = 0xFFFFFFFF; | ||
| 68 | regs.stencil_back_mask = 0xFFFFFFFF; | ||
| 56 | } | 69 | } |
| 57 | 70 | ||
| 58 | void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { | 71 | void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 557795d0f..91ca57883 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -345,6 +345,14 @@ public: | |||
| 345 | Invert = 6, | 345 | Invert = 6, |
| 346 | IncrWrap = 7, | 346 | IncrWrap = 7, |
| 347 | DecrWrap = 8, | 347 | DecrWrap = 8, |
| 348 | KeepOGL = 0x1E00, | ||
| 349 | ZeroOGL = 0, | ||
| 350 | ReplaceOGL = 0x1E01, | ||
| 351 | IncrOGL = 0x1E02, | ||
| 352 | DecrOGL = 0x1E03, | ||
| 353 | InvertOGL = 0x150A, | ||
| 354 | IncrWrapOGL = 0x8507, | ||
| 355 | DecrWrapOGL = 0x8508, | ||
| 348 | }; | 356 | }; |
| 349 | 357 | ||
| 350 | enum class MemoryLayout : u32 { | 358 | enum class MemoryLayout : u32 { |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index a99f2b1f9..54cc47a9b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -140,7 +140,7 @@ void RasterizerOpenGL::SetupVertexFormat() { | |||
| 140 | if (is_cache_miss) { | 140 | if (is_cache_miss) { |
| 141 | VAO.Create(); | 141 | VAO.Create(); |
| 142 | state.draw.vertex_array = VAO.handle; | 142 | state.draw.vertex_array = VAO.handle; |
| 143 | state.Apply(); | 143 | state.ApplyVertexBufferState(); |
| 144 | 144 | ||
| 145 | // The index buffer binding is stored within the VAO. Stupid OpenGL, but easy to work | 145 | // The index buffer binding is stored within the VAO. Stupid OpenGL, but easy to work |
| 146 | // around. | 146 | // around. |
| @@ -182,7 +182,7 @@ void RasterizerOpenGL::SetupVertexFormat() { | |||
| 182 | } | 182 | } |
| 183 | } | 183 | } |
| 184 | state.draw.vertex_array = VAO.handle; | 184 | state.draw.vertex_array = VAO.handle; |
| 185 | state.Apply(); | 185 | state.ApplyVertexBufferState(); |
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | void RasterizerOpenGL::SetupVertexBuffer() { | 188 | void RasterizerOpenGL::SetupVertexBuffer() { |
| @@ -342,8 +342,6 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { | |||
| 342 | index++; | 342 | index++; |
| 343 | } | 343 | } |
| 344 | } | 344 | } |
| 345 | |||
| 346 | state.Apply(); | ||
| 347 | } | 345 | } |
| 348 | 346 | ||
| 349 | std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { | 347 | std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { |
| @@ -412,8 +410,8 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { | |||
| 412 | cached_pages.add({pages_interval, delta}); | 410 | cached_pages.add({pages_interval, delta}); |
| 413 | } | 411 | } |
| 414 | 412 | ||
| 415 | void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb, | 413 | void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool using_color_fb, |
| 416 | bool preserve_contents, | 414 | bool using_depth_fb, bool preserve_contents, |
| 417 | std::optional<std::size_t> single_color_target) { | 415 | std::optional<std::size_t> single_color_target) { |
| 418 | MICROPROFILE_SCOPE(OpenGL_Framebuffer); | 416 | MICROPROFILE_SCOPE(OpenGL_Framebuffer); |
| 419 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 417 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| @@ -429,9 +427,9 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep | |||
| 429 | ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented"); | 427 | ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented"); |
| 430 | 428 | ||
| 431 | // Bind the framebuffer surfaces | 429 | // Bind the framebuffer surfaces |
| 432 | state.draw.draw_framebuffer = framebuffer.handle; | 430 | current_state.draw.draw_framebuffer = framebuffer.handle; |
| 433 | state.Apply(); | 431 | current_state.ApplyFramebufferState(); |
| 434 | state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0; | 432 | current_state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0; |
| 435 | 433 | ||
| 436 | if (using_color_fb) { | 434 | if (using_color_fb) { |
| 437 | if (single_color_target) { | 435 | if (single_color_target) { |
| @@ -509,10 +507,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep | |||
| 509 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, | 507 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, |
| 510 | 0); | 508 | 0); |
| 511 | } | 509 | } |
| 512 | 510 | SyncViewport(current_state); | |
| 513 | SyncViewport(); | ||
| 514 | |||
| 515 | state.Apply(); | ||
| 516 | } | 511 | } |
| 517 | 512 | ||
| 518 | void RasterizerOpenGL::Clear() { | 513 | void RasterizerOpenGL::Clear() { |
| @@ -525,22 +520,23 @@ void RasterizerOpenGL::Clear() { | |||
| 525 | bool use_stencil{}; | 520 | bool use_stencil{}; |
| 526 | 521 | ||
| 527 | OpenGLState clear_state; | 522 | OpenGLState clear_state; |
| 528 | clear_state.draw.draw_framebuffer = framebuffer.handle; | ||
| 529 | clear_state.color_mask[0].red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE; | ||
| 530 | clear_state.color_mask[0].green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE; | ||
| 531 | clear_state.color_mask[0].blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; | ||
| 532 | clear_state.color_mask[0].alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; | ||
| 533 | |||
| 534 | if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || | 523 | if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || |
| 535 | regs.clear_buffers.A) { | 524 | regs.clear_buffers.A) { |
| 536 | use_color = true; | 525 | use_color = true; |
| 537 | } | 526 | } |
| 527 | if (use_color) { | ||
| 528 | clear_state.color_mask[0].red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE; | ||
| 529 | clear_state.color_mask[0].green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE; | ||
| 530 | clear_state.color_mask[0].blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; | ||
| 531 | clear_state.color_mask[0].alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; | ||
| 532 | } | ||
| 538 | if (regs.clear_buffers.Z) { | 533 | if (regs.clear_buffers.Z) { |
| 539 | ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!"); | 534 | ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!"); |
| 540 | use_depth = true; | 535 | use_depth = true; |
| 541 | 536 | ||
| 542 | // Always enable the depth write when clearing the depth buffer. The depth write mask is | 537 | // Always enable the depth write when clearing the depth buffer. The depth write mask is |
| 543 | // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to true. | 538 | // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to |
| 539 | // true. | ||
| 544 | clear_state.depth.test_enabled = true; | 540 | clear_state.depth.test_enabled = true; |
| 545 | clear_state.depth.test_func = GL_ALWAYS; | 541 | clear_state.depth.test_func = GL_ALWAYS; |
| 546 | } | 542 | } |
| @@ -557,11 +553,8 @@ void RasterizerOpenGL::Clear() { | |||
| 557 | 553 | ||
| 558 | ScopeAcquireGLContext acquire_context{emu_window}; | 554 | ScopeAcquireGLContext acquire_context{emu_window}; |
| 559 | 555 | ||
| 560 | ConfigureFramebuffers(use_color, use_depth || use_stencil, false, | 556 | ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false, |
| 561 | regs.clear_buffers.RT.Value()); | 557 | regs.clear_buffers.RT.Value()); |
| 562 | // Copy the sRGB setting to the clear state to avoid problem with | ||
| 563 | // specific driver implementations | ||
| 564 | clear_state.framebuffer_srgb.enabled = state.framebuffer_srgb.enabled; | ||
| 565 | clear_state.Apply(); | 558 | clear_state.Apply(); |
| 566 | 559 | ||
| 567 | if (use_color) { | 560 | if (use_color) { |
| @@ -587,7 +580,7 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 587 | 580 | ||
| 588 | ScopeAcquireGLContext acquire_context{emu_window}; | 581 | ScopeAcquireGLContext acquire_context{emu_window}; |
| 589 | 582 | ||
| 590 | ConfigureFramebuffers(); | 583 | ConfigureFramebuffers(state); |
| 591 | SyncColorMask(); | 584 | SyncColorMask(); |
| 592 | SyncDepthTestState(); | 585 | SyncDepthTestState(); |
| 593 | SyncStencilTestState(); | 586 | SyncStencilTestState(); |
| @@ -608,7 +601,7 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 608 | const bool is_indexed = accelerate_draw == AccelDraw::Indexed; | 601 | const bool is_indexed = accelerate_draw == AccelDraw::Indexed; |
| 609 | 602 | ||
| 610 | state.draw.vertex_buffer = buffer_cache.GetHandle(); | 603 | state.draw.vertex_buffer = buffer_cache.GetHandle(); |
| 611 | state.Apply(); | 604 | state.ApplyVertexBufferState(); |
| 612 | 605 | ||
| 613 | std::size_t buffer_size = CalculateVertexArraysSize(); | 606 | std::size_t buffer_size = CalculateVertexArraysSize(); |
| 614 | 607 | ||
| @@ -740,9 +733,9 @@ void RasterizerOpenGL::SamplerInfo::Create() { | |||
| 740 | glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER); | 733 | glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER); |
| 741 | } | 734 | } |
| 742 | 735 | ||
| 743 | void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) { | 736 | void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::FullTextureInfo& info) { |
| 744 | const GLuint s = sampler.handle; | 737 | const GLuint s = sampler.handle; |
| 745 | 738 | const Tegra::Texture::TSCEntry& config = info.tsc; | |
| 746 | if (mag_filter != config.mag_filter) { | 739 | if (mag_filter != config.mag_filter) { |
| 747 | mag_filter = config.mag_filter; | 740 | mag_filter = config.mag_filter; |
| 748 | glSamplerParameteri( | 741 | glSamplerParameteri( |
| @@ -793,6 +786,22 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr | |||
| 793 | glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data()); | 786 | glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data()); |
| 794 | } | 787 | } |
| 795 | } | 788 | } |
| 789 | if (info.tic.use_header_opt_control == 0) { | ||
| 790 | if (GLAD_GL_ARB_texture_filter_anisotropic) { | ||
| 791 | glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY, | ||
| 792 | static_cast<float>(1 << info.tic.max_anisotropy.Value())); | ||
| 793 | } else if (GLAD_GL_EXT_texture_filter_anisotropic) { | ||
| 794 | glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT, | ||
| 795 | static_cast<float>(1 << info.tic.max_anisotropy.Value())); | ||
| 796 | } | ||
| 797 | glSamplerParameterf(s, GL_TEXTURE_MIN_LOD, | ||
| 798 | static_cast<float>(info.tic.res_min_mip_level.Value())); | ||
| 799 | glSamplerParameterf(s, GL_TEXTURE_MAX_LOD, | ||
| 800 | static_cast<float>(info.tic.res_max_mip_level.Value() == 0 | ||
| 801 | ? 16 | ||
| 802 | : info.tic.res_max_mip_level.Value())); | ||
| 803 | glSamplerParameterf(s, GL_TEXTURE_LOD_BIAS, info.tic.mip_lod_bias.Value() / 256.f); | ||
| 804 | } | ||
| 796 | } | 805 | } |
| 797 | 806 | ||
| 798 | u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shader, | 807 | u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shader, |
| @@ -890,7 +899,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, | |||
| 890 | continue; | 899 | continue; |
| 891 | } | 900 | } |
| 892 | 901 | ||
| 893 | texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); | 902 | texture_samplers[current_bindpoint].SyncWithConfig(texture); |
| 894 | Surface surface = res_cache.GetTextureSurface(texture, entry); | 903 | Surface surface = res_cache.GetTextureSurface(texture, entry); |
| 895 | if (surface != nullptr) { | 904 | if (surface != nullptr) { |
| 896 | state.texture_units[current_bindpoint].texture = surface->Texture().handle; | 905 | state.texture_units[current_bindpoint].texture = surface->Texture().handle; |
| @@ -912,11 +921,11 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, | |||
| 912 | return current_unit + static_cast<u32>(entries.size()); | 921 | return current_unit + static_cast<u32>(entries.size()); |
| 913 | } | 922 | } |
| 914 | 923 | ||
| 915 | void RasterizerOpenGL::SyncViewport() { | 924 | void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { |
| 916 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 925 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 917 | for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { | 926 | for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { |
| 918 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()}; | 927 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()}; |
| 919 | auto& viewport = state.viewports[i]; | 928 | auto& viewport = current_state.viewports[i]; |
| 920 | viewport.x = viewport_rect.left; | 929 | viewport.x = viewport_rect.left; |
| 921 | viewport.y = viewport_rect.bottom; | 930 | viewport.y = viewport_rect.bottom; |
| 922 | viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth()); | 931 | viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth()); |
| @@ -985,9 +994,6 @@ void RasterizerOpenGL::SyncStencilTestState() { | |||
| 985 | return; | 994 | return; |
| 986 | } | 995 | } |
| 987 | 996 | ||
| 988 | // TODO(bunnei): Verify behavior when this is not set | ||
| 989 | ASSERT(regs.stencil_two_side_enable); | ||
| 990 | |||
| 991 | state.stencil.front.test_func = MaxwellToGL::ComparisonOp(regs.stencil_front_func_func); | 997 | state.stencil.front.test_func = MaxwellToGL::ComparisonOp(regs.stencil_front_func_func); |
| 992 | state.stencil.front.test_ref = regs.stencil_front_func_ref; | 998 | state.stencil.front.test_ref = regs.stencil_front_func_ref; |
| 993 | state.stencil.front.test_mask = regs.stencil_front_func_mask; | 999 | state.stencil.front.test_mask = regs.stencil_front_func_mask; |
| @@ -995,14 +1001,23 @@ void RasterizerOpenGL::SyncStencilTestState() { | |||
| 995 | state.stencil.front.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_front_op_zfail); | 1001 | state.stencil.front.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_front_op_zfail); |
| 996 | state.stencil.front.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_front_op_zpass); | 1002 | state.stencil.front.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_front_op_zpass); |
| 997 | state.stencil.front.write_mask = regs.stencil_front_mask; | 1003 | state.stencil.front.write_mask = regs.stencil_front_mask; |
| 998 | 1004 | if (regs.stencil_two_side_enable) { | |
| 999 | state.stencil.back.test_func = MaxwellToGL::ComparisonOp(regs.stencil_back_func_func); | 1005 | state.stencil.back.test_func = MaxwellToGL::ComparisonOp(regs.stencil_back_func_func); |
| 1000 | state.stencil.back.test_ref = regs.stencil_back_func_ref; | 1006 | state.stencil.back.test_ref = regs.stencil_back_func_ref; |
| 1001 | state.stencil.back.test_mask = regs.stencil_back_func_mask; | 1007 | state.stencil.back.test_mask = regs.stencil_back_func_mask; |
| 1002 | state.stencil.back.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_fail); | 1008 | state.stencil.back.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_fail); |
| 1003 | state.stencil.back.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_zfail); | 1009 | state.stencil.back.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_zfail); |
| 1004 | state.stencil.back.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_back_op_zpass); | 1010 | state.stencil.back.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_back_op_zpass); |
| 1005 | state.stencil.back.write_mask = regs.stencil_back_mask; | 1011 | state.stencil.back.write_mask = regs.stencil_back_mask; |
| 1012 | } else { | ||
| 1013 | state.stencil.back.test_func = GL_ALWAYS; | ||
| 1014 | state.stencil.back.test_ref = 0; | ||
| 1015 | state.stencil.back.test_mask = 0xFFFFFFFF; | ||
| 1016 | state.stencil.back.write_mask = 0xFFFFFFFF; | ||
| 1017 | state.stencil.back.action_stencil_fail = GL_KEEP; | ||
| 1018 | state.stencil.back.action_depth_fail = GL_KEEP; | ||
| 1019 | state.stencil.back.action_depth_pass = GL_KEEP; | ||
| 1020 | } | ||
| 1006 | } | 1021 | } |
| 1007 | 1022 | ||
| 1008 | void RasterizerOpenGL::SyncColorMask() { | 1023 | void RasterizerOpenGL::SyncColorMask() { |
| @@ -1114,9 +1129,8 @@ void RasterizerOpenGL::CheckAlphaTests() { | |||
| 1114 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1129 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 1115 | 1130 | ||
| 1116 | if (regs.alpha_test_enabled != 0 && regs.rt_control.count > 1) { | 1131 | if (regs.alpha_test_enabled != 0 && regs.rt_control.count > 1) { |
| 1117 | LOG_CRITICAL( | 1132 | LOG_CRITICAL(Render_OpenGL, "Alpha Testing is enabled with Multiple Render Targets, " |
| 1118 | Render_OpenGL, | 1133 | "this behavior is undefined."); |
| 1119 | "Alpha Testing is enabled with Multiple Render Targets, this behavior is undefined."); | ||
| 1120 | UNREACHABLE(); | 1134 | UNREACHABLE(); |
| 1121 | } | 1135 | } |
| 1122 | } | 1136 | } |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 5eee5f088..8ef0f6c12 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -88,7 +88,7 @@ private: | |||
| 88 | /// SamplerInfo struct. | 88 | /// SamplerInfo struct. |
| 89 | void Create(); | 89 | void Create(); |
| 90 | /// Syncs the sampler object with the config, updating any necessary state. | 90 | /// Syncs the sampler object with the config, updating any necessary state. |
| 91 | void SyncWithConfig(const Tegra::Texture::TSCEntry& config); | 91 | void SyncWithConfig(const Tegra::Texture::FullTextureInfo& info); |
| 92 | 92 | ||
| 93 | private: | 93 | private: |
| 94 | Tegra::Texture::TextureFilter mag_filter; | 94 | Tegra::Texture::TextureFilter mag_filter; |
| @@ -109,8 +109,8 @@ private: | |||
| 109 | * @param preserve_contents If true, tries to preserve data from a previously used framebuffer. | 109 | * @param preserve_contents If true, tries to preserve data from a previously used framebuffer. |
| 110 | * @param single_color_target Specifies if a single color buffer target should be used. | 110 | * @param single_color_target Specifies if a single color buffer target should be used. |
| 111 | */ | 111 | */ |
| 112 | void ConfigureFramebuffers(bool use_color_fb = true, bool using_depth_fb = true, | 112 | void ConfigureFramebuffers(OpenGLState& current_state, bool use_color_fb = true, |
| 113 | bool preserve_contents = true, | 113 | bool using_depth_fb = true, bool preserve_contents = true, |
| 114 | std::optional<std::size_t> single_color_target = {}); | 114 | std::optional<std::size_t> single_color_target = {}); |
| 115 | 115 | ||
| 116 | /* | 116 | /* |
| @@ -134,7 +134,7 @@ private: | |||
| 134 | GLenum primitive_mode, u32 current_unit); | 134 | GLenum primitive_mode, u32 current_unit); |
| 135 | 135 | ||
| 136 | /// Syncs the viewport and depth range to match the guest state | 136 | /// Syncs the viewport and depth range to match the guest state |
| 137 | void SyncViewport(); | 137 | void SyncViewport(OpenGLState& current_state); |
| 138 | 138 | ||
| 139 | /// Syncs the clip enabled status to match the guest state | 139 | /// Syncs the clip enabled status to match the guest state |
| 140 | void SyncClipEnabled(); | 140 | void SyncClipEnabled(); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index c8864cce8..894f4f294 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -580,7 +580,7 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, | |||
| 580 | state.draw.draw_framebuffer = draw_fb_handle; | 580 | state.draw.draw_framebuffer = draw_fb_handle; |
| 581 | // Set sRGB enabled if the destination surfaces need it | 581 | // Set sRGB enabled if the destination surfaces need it |
| 582 | state.framebuffer_srgb.enabled = dst_params.srgb_conversion; | 582 | state.framebuffer_srgb.enabled = dst_params.srgb_conversion; |
| 583 | state.Apply(); | 583 | state.ApplyFramebufferState(); |
| 584 | 584 | ||
| 585 | u32 buffers{}; | 585 | u32 buffers{}; |
| 586 | 586 | ||
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 9517285e5..2635f2b0c 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -427,7 +427,7 @@ void OpenGLState::ApplySamplers() const { | |||
| 427 | } | 427 | } |
| 428 | } | 428 | } |
| 429 | 429 | ||
| 430 | void OpenGLState::Apply() const { | 430 | void OpenGLState::ApplyFramebufferState() const { |
| 431 | // Framebuffer | 431 | // Framebuffer |
| 432 | if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { | 432 | if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { |
| 433 | glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); | 433 | glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); |
| @@ -435,7 +435,9 @@ void OpenGLState::Apply() const { | |||
| 435 | if (draw.draw_framebuffer != cur_state.draw.draw_framebuffer) { | 435 | if (draw.draw_framebuffer != cur_state.draw.draw_framebuffer) { |
| 436 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw.draw_framebuffer); | 436 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw.draw_framebuffer); |
| 437 | } | 437 | } |
| 438 | } | ||
| 438 | 439 | ||
| 440 | void OpenGLState::ApplyVertexBufferState() const { | ||
| 439 | // Vertex array | 441 | // Vertex array |
| 440 | if (draw.vertex_array != cur_state.draw.vertex_array) { | 442 | if (draw.vertex_array != cur_state.draw.vertex_array) { |
| 441 | glBindVertexArray(draw.vertex_array); | 443 | glBindVertexArray(draw.vertex_array); |
| @@ -445,7 +447,11 @@ void OpenGLState::Apply() const { | |||
| 445 | if (draw.vertex_buffer != cur_state.draw.vertex_buffer) { | 447 | if (draw.vertex_buffer != cur_state.draw.vertex_buffer) { |
| 446 | glBindBuffer(GL_ARRAY_BUFFER, draw.vertex_buffer); | 448 | glBindBuffer(GL_ARRAY_BUFFER, draw.vertex_buffer); |
| 447 | } | 449 | } |
| 450 | } | ||
| 448 | 451 | ||
| 452 | void OpenGLState::Apply() const { | ||
| 453 | ApplyFramebufferState(); | ||
| 454 | ApplyVertexBufferState(); | ||
| 449 | // Uniform buffer | 455 | // Uniform buffer |
| 450 | if (draw.uniform_buffer != cur_state.draw.uniform_buffer) { | 456 | if (draw.uniform_buffer != cur_state.draw.uniform_buffer) { |
| 451 | glBindBuffer(GL_UNIFORM_BUFFER, draw.uniform_buffer); | 457 | glBindBuffer(GL_UNIFORM_BUFFER, draw.uniform_buffer); |
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index b8cf1f637..eacca0b9c 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -181,6 +181,10 @@ public: | |||
| 181 | } | 181 | } |
| 182 | /// Apply this state as the current OpenGL state | 182 | /// Apply this state as the current OpenGL state |
| 183 | void Apply() const; | 183 | void Apply() const; |
| 184 | /// Apply only the state afecting the framebuffer | ||
| 185 | void ApplyFramebufferState() const; | ||
| 186 | /// Apply only the state afecting the vertex buffer | ||
| 187 | void ApplyVertexBufferState() const; | ||
| 184 | /// Set the initial OpenGL state | 188 | /// Set the initial OpenGL state |
| 185 | static void ApplyDefaultState(); | 189 | static void ApplyDefaultState(); |
| 186 | /// Resets any references to the given resource | 190 | /// Resets any references to the given resource |
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 87d511c38..3ce2cc6d2 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h | |||
| @@ -159,10 +159,8 @@ inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode, | |||
| 159 | } | 159 | } |
| 160 | } | 160 | } |
| 161 | } | 161 | } |
| 162 | LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}", | 162 | LOG_ERROR(Render_OpenGL, "Unimplemented texture filter mode={}", static_cast<u32>(filter_mode)); |
| 163 | static_cast<u32>(filter_mode)); | 163 | return GL_LINEAR; |
| 164 | UNREACHABLE(); | ||
| 165 | return {}; | ||
| 166 | } | 164 | } |
| 167 | 165 | ||
| 168 | inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { | 166 | inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { |
| @@ -183,9 +181,8 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { | |||
| 183 | case Tegra::Texture::WrapMode::MirrorOnceClampToEdge: | 181 | case Tegra::Texture::WrapMode::MirrorOnceClampToEdge: |
| 184 | return GL_MIRROR_CLAMP_TO_EDGE; | 182 | return GL_MIRROR_CLAMP_TO_EDGE; |
| 185 | } | 183 | } |
| 186 | LOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode)); | 184 | LOG_ERROR(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode)); |
| 187 | UNREACHABLE(); | 185 | return GL_REPEAT; |
| 188 | return {}; | ||
| 189 | } | 186 | } |
| 190 | 187 | ||
| 191 | inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) { | 188 | inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) { |
| @@ -207,10 +204,9 @@ inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) { | |||
| 207 | case Tegra::Texture::DepthCompareFunc::Always: | 204 | case Tegra::Texture::DepthCompareFunc::Always: |
| 208 | return GL_ALWAYS; | 205 | return GL_ALWAYS; |
| 209 | } | 206 | } |
| 210 | LOG_CRITICAL(Render_OpenGL, "Unimplemented texture depth compare function ={}", | 207 | LOG_ERROR(Render_OpenGL, "Unimplemented texture depth compare function ={}", |
| 211 | static_cast<u32>(func)); | 208 | static_cast<u32>(func)); |
| 212 | UNREACHABLE(); | 209 | return GL_GREATER; |
| 213 | return {}; | ||
| 214 | } | 210 | } |
| 215 | 211 | ||
| 216 | inline GLenum BlendEquation(Maxwell::Blend::Equation equation) { | 212 | inline GLenum BlendEquation(Maxwell::Blend::Equation equation) { |
| @@ -226,9 +222,8 @@ inline GLenum BlendEquation(Maxwell::Blend::Equation equation) { | |||
| 226 | case Maxwell::Blend::Equation::Max: | 222 | case Maxwell::Blend::Equation::Max: |
| 227 | return GL_MAX; | 223 | return GL_MAX; |
| 228 | } | 224 | } |
| 229 | LOG_CRITICAL(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation)); | 225 | LOG_ERROR(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation)); |
| 230 | UNREACHABLE(); | 226 | return GL_FUNC_ADD; |
| 231 | return {}; | ||
| 232 | } | 227 | } |
| 233 | 228 | ||
| 234 | inline GLenum BlendFunc(Maxwell::Blend::Factor factor) { | 229 | inline GLenum BlendFunc(Maxwell::Blend::Factor factor) { |
| @@ -291,9 +286,8 @@ inline GLenum BlendFunc(Maxwell::Blend::Factor factor) { | |||
| 291 | case Maxwell::Blend::Factor::OneMinusConstantAlphaGL: | 286 | case Maxwell::Blend::Factor::OneMinusConstantAlphaGL: |
| 292 | return GL_ONE_MINUS_CONSTANT_ALPHA; | 287 | return GL_ONE_MINUS_CONSTANT_ALPHA; |
| 293 | } | 288 | } |
| 294 | LOG_CRITICAL(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor)); | 289 | LOG_ERROR(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor)); |
| 295 | UNREACHABLE(); | 290 | return GL_ZERO; |
| 296 | return {}; | ||
| 297 | } | 291 | } |
| 298 | 292 | ||
| 299 | inline GLenum SwizzleSource(Tegra::Texture::SwizzleSource source) { | 293 | inline GLenum SwizzleSource(Tegra::Texture::SwizzleSource source) { |
| @@ -312,9 +306,8 @@ inline GLenum SwizzleSource(Tegra::Texture::SwizzleSource source) { | |||
| 312 | case Tegra::Texture::SwizzleSource::OneFloat: | 306 | case Tegra::Texture::SwizzleSource::OneFloat: |
| 313 | return GL_ONE; | 307 | return GL_ONE; |
| 314 | } | 308 | } |
| 315 | LOG_CRITICAL(Render_OpenGL, "Unimplemented swizzle source={}", static_cast<u32>(source)); | 309 | LOG_ERROR(Render_OpenGL, "Unimplemented swizzle source={}", static_cast<u32>(source)); |
| 316 | UNREACHABLE(); | 310 | return GL_ZERO; |
| 317 | return {}; | ||
| 318 | } | 311 | } |
| 319 | 312 | ||
| 320 | inline GLenum ComparisonOp(Maxwell::ComparisonOp comparison) { | 313 | inline GLenum ComparisonOp(Maxwell::ComparisonOp comparison) { |
| @@ -344,33 +337,39 @@ inline GLenum ComparisonOp(Maxwell::ComparisonOp comparison) { | |||
| 344 | case Maxwell::ComparisonOp::AlwaysOld: | 337 | case Maxwell::ComparisonOp::AlwaysOld: |
| 345 | return GL_ALWAYS; | 338 | return GL_ALWAYS; |
| 346 | } | 339 | } |
| 347 | LOG_CRITICAL(Render_OpenGL, "Unimplemented comparison op={}", static_cast<u32>(comparison)); | 340 | LOG_ERROR(Render_OpenGL, "Unimplemented comparison op={}", static_cast<u32>(comparison)); |
| 348 | UNREACHABLE(); | 341 | return GL_ALWAYS; |
| 349 | return {}; | ||
| 350 | } | 342 | } |
| 351 | 343 | ||
| 352 | inline GLenum StencilOp(Maxwell::StencilOp stencil) { | 344 | inline GLenum StencilOp(Maxwell::StencilOp stencil) { |
| 353 | switch (stencil) { | 345 | switch (stencil) { |
| 354 | case Maxwell::StencilOp::Keep: | 346 | case Maxwell::StencilOp::Keep: |
| 347 | case Maxwell::StencilOp::KeepOGL: | ||
| 355 | return GL_KEEP; | 348 | return GL_KEEP; |
| 356 | case Maxwell::StencilOp::Zero: | 349 | case Maxwell::StencilOp::Zero: |
| 350 | case Maxwell::StencilOp::ZeroOGL: | ||
| 357 | return GL_ZERO; | 351 | return GL_ZERO; |
| 358 | case Maxwell::StencilOp::Replace: | 352 | case Maxwell::StencilOp::Replace: |
| 353 | case Maxwell::StencilOp::ReplaceOGL: | ||
| 359 | return GL_REPLACE; | 354 | return GL_REPLACE; |
| 360 | case Maxwell::StencilOp::Incr: | 355 | case Maxwell::StencilOp::Incr: |
| 356 | case Maxwell::StencilOp::IncrOGL: | ||
| 361 | return GL_INCR; | 357 | return GL_INCR; |
| 362 | case Maxwell::StencilOp::Decr: | 358 | case Maxwell::StencilOp::Decr: |
| 359 | case Maxwell::StencilOp::DecrOGL: | ||
| 363 | return GL_DECR; | 360 | return GL_DECR; |
| 364 | case Maxwell::StencilOp::Invert: | 361 | case Maxwell::StencilOp::Invert: |
| 362 | case Maxwell::StencilOp::InvertOGL: | ||
| 365 | return GL_INVERT; | 363 | return GL_INVERT; |
| 366 | case Maxwell::StencilOp::IncrWrap: | 364 | case Maxwell::StencilOp::IncrWrap: |
| 365 | case Maxwell::StencilOp::IncrWrapOGL: | ||
| 367 | return GL_INCR_WRAP; | 366 | return GL_INCR_WRAP; |
| 368 | case Maxwell::StencilOp::DecrWrap: | 367 | case Maxwell::StencilOp::DecrWrap: |
| 368 | case Maxwell::StencilOp::DecrWrapOGL: | ||
| 369 | return GL_DECR_WRAP; | 369 | return GL_DECR_WRAP; |
| 370 | } | 370 | } |
| 371 | LOG_CRITICAL(Render_OpenGL, "Unimplemented stencil op={}", static_cast<u32>(stencil)); | 371 | LOG_ERROR(Render_OpenGL, "Unimplemented stencil op={}", static_cast<u32>(stencil)); |
| 372 | UNREACHABLE(); | 372 | return GL_KEEP; |
| 373 | return {}; | ||
| 374 | } | 373 | } |
| 375 | 374 | ||
| 376 | inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) { | 375 | inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) { |
| @@ -380,9 +379,8 @@ inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) { | |||
| 380 | case Maxwell::Cull::FrontFace::CounterClockWise: | 379 | case Maxwell::Cull::FrontFace::CounterClockWise: |
| 381 | return GL_CCW; | 380 | return GL_CCW; |
| 382 | } | 381 | } |
| 383 | LOG_CRITICAL(Render_OpenGL, "Unimplemented front face cull={}", static_cast<u32>(front_face)); | 382 | LOG_ERROR(Render_OpenGL, "Unimplemented front face cull={}", static_cast<u32>(front_face)); |
| 384 | UNREACHABLE(); | 383 | return GL_CCW; |
| 385 | return {}; | ||
| 386 | } | 384 | } |
| 387 | 385 | ||
| 388 | inline GLenum CullFace(Maxwell::Cull::CullFace cull_face) { | 386 | inline GLenum CullFace(Maxwell::Cull::CullFace cull_face) { |
| @@ -394,9 +392,8 @@ inline GLenum CullFace(Maxwell::Cull::CullFace cull_face) { | |||
| 394 | case Maxwell::Cull::CullFace::FrontAndBack: | 392 | case Maxwell::Cull::CullFace::FrontAndBack: |
| 395 | return GL_FRONT_AND_BACK; | 393 | return GL_FRONT_AND_BACK; |
| 396 | } | 394 | } |
| 397 | LOG_CRITICAL(Render_OpenGL, "Unimplemented cull face={}", static_cast<u32>(cull_face)); | 395 | LOG_ERROR(Render_OpenGL, "Unimplemented cull face={}", static_cast<u32>(cull_face)); |
| 398 | UNREACHABLE(); | 396 | return GL_BACK; |
| 399 | return {}; | ||
| 400 | } | 397 | } |
| 401 | 398 | ||
| 402 | inline GLenum LogicOp(Maxwell::LogicOperation operation) { | 399 | inline GLenum LogicOp(Maxwell::LogicOperation operation) { |
| @@ -434,9 +431,8 @@ inline GLenum LogicOp(Maxwell::LogicOperation operation) { | |||
| 434 | case Maxwell::LogicOperation::Set: | 431 | case Maxwell::LogicOperation::Set: |
| 435 | return GL_SET; | 432 | return GL_SET; |
| 436 | } | 433 | } |
| 437 | LOG_CRITICAL(Render_OpenGL, "Unimplemented logic operation={}", static_cast<u32>(operation)); | 434 | LOG_ERROR(Render_OpenGL, "Unimplemented logic operation={}", static_cast<u32>(operation)); |
| 438 | UNREACHABLE(); | 435 | return GL_COPY; |
| 439 | return {}; | ||
| 440 | } | 436 | } |
| 441 | 437 | ||
| 442 | } // namespace MaxwellToGL | 438 | } // namespace MaxwellToGL |
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index d12d2ecb8..e199d019a 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h | |||
| @@ -168,20 +168,29 @@ struct TICEntry { | |||
| 168 | 168 | ||
| 169 | // High 16 bits of the pitch value | 169 | // High 16 bits of the pitch value |
| 170 | BitField<0, 16, u32> pitch_high; | 170 | BitField<0, 16, u32> pitch_high; |
| 171 | 171 | BitField<26, 1, u32> use_header_opt_control; | |
| 172 | BitField<27, 1, u32> depth_texture; | ||
| 172 | BitField<28, 4, u32> max_mip_level; | 173 | BitField<28, 4, u32> max_mip_level; |
| 173 | }; | 174 | }; |
| 174 | union { | 175 | union { |
| 175 | BitField<0, 16, u32> width_minus_1; | 176 | BitField<0, 16, u32> width_minus_1; |
| 176 | BitField<22, 1, u32> srgb_conversion; | 177 | BitField<22, 1, u32> srgb_conversion; |
| 177 | BitField<23, 4, TextureType> texture_type; | 178 | BitField<23, 4, TextureType> texture_type; |
| 179 | BitField<29, 3, u32> border_size; | ||
| 178 | }; | 180 | }; |
| 179 | union { | 181 | union { |
| 180 | BitField<0, 16, u32> height_minus_1; | 182 | BitField<0, 16, u32> height_minus_1; |
| 181 | BitField<16, 15, u32> depth_minus_1; | 183 | BitField<16, 15, u32> depth_minus_1; |
| 182 | }; | 184 | }; |
| 185 | union { | ||
| 186 | BitField<6, 13, u32> mip_lod_bias; | ||
| 187 | BitField<27, 3, u32> max_anisotropy; | ||
| 188 | }; | ||
| 183 | 189 | ||
| 184 | INSERT_PADDING_BYTES(8); | 190 | union { |
| 191 | BitField<0, 4, u32> res_min_mip_level; | ||
| 192 | BitField<4, 4, u32> res_max_mip_level; | ||
| 193 | }; | ||
| 185 | 194 | ||
| 186 | GPUVAddr Address() const { | 195 | GPUVAddr Address() const { |
| 187 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low); | 196 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low); |