u32 GLGSRender::get_zcull_stats(u32 type) { if (g_cfg.video.disable_zcull_queries) return 0u; if (zcull_task_queue.active_query && zcull_task_queue.active_query->active && current_zcull_stats.zpass_pixel_cnt == 0 && type == CELL_GCM_ZPASS_PIXEL_CNT) { //The zcull unit is still bound as the read is happening and there are no results ready check_zcull_status(false, true); //close current query check_zcull_status(false, false); //start new query since stat counting is still active } switch (type) { case CELL_GCM_ZPASS_PIXEL_CNT: { if (current_zcull_stats.zpass_pixel_cnt > 0) return UINT16_MAX; synchronize_zcull_stats(true); return (current_zcull_stats.zpass_pixel_cnt > 0)? UINT16_MAX : 0; } case CELL_GCM_ZCULL_STATS: case CELL_GCM_ZCULL_STATS1: case CELL_GCM_ZCULL_STATS2: //TODO return UINT16_MAX; case CELL_GCM_ZCULL_STATS3: { //Some kind of inverse value if (current_zcull_stats.zpass_pixel_cnt > 0) return 0; synchronize_zcull_stats(true); return (current_zcull_stats.zpass_pixel_cnt > 0) ? 0 : UINT16_MAX; } default: LOG_ERROR(RSX, "Unknown zcull stat type %d", type); return 0; } }
void GLGSRender::clear_zcull_stats(u32 type) { if (g_cfg.video.disable_zcull_queries) return; if (type == CELL_GCM_ZPASS_PIXEL_CNT) { if (zcull_task_queue.active_query && zcull_task_queue.active_query->active && zcull_task_queue.active_query->num_draws > 0) { //discard active query results check_zcull_status(false, true); zcull_task_queue.active_query->pending = false; //re-enable cull stats if stats are enabled check_zcull_status(false, false); } current_zcull_stats.clear(); } }
u32 GLGSRender::get_zcull_stats(u32 type) { if (g_cfg.video.disable_zcull_queries) return 0u; if (zcull_task_queue.active_query && zcull_task_queue.active_query->active && current_zcull_stats.zpass_pixel_cnt == 0) { //The zcull unit is still bound as the read is happening and there are no results ready check_zcull_status(false, true); } switch (type) { case CELL_GCM_ZPASS_PIXEL_CNT: { if (current_zcull_stats.zpass_pixel_cnt > 0) return UINT32_MAX; //If we have no results, we might as well synchronize here and wait for results to become available synchronize_zcull_stats(true); return (current_zcull_stats.zpass_pixel_cnt > 0)? UINT32_MAX: 0; } case CELL_GCM_ZCULL_STATS: case CELL_GCM_ZCULL_STATS1: case CELL_GCM_ZCULL_STATS2: //TODO return UINT32_MAX; case CELL_GCM_ZCULL_STATS3: { //Some kind of inverse value if (current_zcull_stats.zpass_pixel_cnt > 0) return 0; synchronize_zcull_stats(true); return (current_zcull_stats.zpass_pixel_cnt > 0) ? 0 : UINT32_MAX; } default: LOG_ERROR(RSX, "Unknown zcull stat type %d", type); return 0; } }
void GLGSRender::init_buffers(bool skip_reading) { if (draw_fbo && !m_rtts_dirty) { set_viewport(); return; } //We are about to change buffers, flush any pending requests for the old buffers synchronize_buffers(); m_rtts_dirty = false; zcull_surface_active = false; const u16 clip_horizontal = rsx::method_registers.surface_clip_width(); const u16 clip_vertical = rsx::method_registers.surface_clip_height(); if (clip_horizontal == 0 || clip_vertical == 0) { LOG_ERROR(RSX, "Invalid framebuffer setup, w=%d, h=%d", clip_horizontal, clip_vertical); framebuffer_status_valid = false; return; } const auto pitchs = get_pitchs(); const auto surface_format = rsx::method_registers.surface_color(); const auto depth_format = rsx::method_registers.surface_depth_fmt(); const auto surface_addresses = get_color_surface_addresses(); const auto depth_address = get_zeta_surface_address(); m_rtts.prepare_render_target(nullptr, surface_format, depth_format, clip_horizontal, clip_vertical, rsx::method_registers.surface_color_target(), surface_addresses, depth_address); draw_fbo.recreate(); for (int i = 0; i < rsx::limits::color_buffers_count; ++i) { if (std::get<0>(m_rtts.m_bound_render_targets[i])) { __glcheck draw_fbo.color[i] = *std::get<1>(m_rtts.m_bound_render_targets[i]); std::get<1>(m_rtts.m_bound_render_targets[i])->set_rsx_pitch(pitchs[i]); surface_info[i] = { surface_addresses[i], pitchs[i], false, surface_format, depth_format, clip_horizontal, clip_vertical }; //Verify pitch given is correct if pitch <= 64 (especially 64) if (pitchs[i] <= 64) { const u16 native_pitch = std::get<1>(m_rtts.m_bound_render_targets[i])->get_native_pitch(); if (native_pitch > pitchs[i]) { LOG_TRACE(RSX, "Bad color surface pitch given: surface_width=%d, format=%d, pitch=%d, native_pitch=%d", clip_horizontal, (u32)surface_format, pitchs[i], native_pitch); //Will not transfer this surface between cell and rsx due to misalignment //TODO: Verify correct behaviour surface_info[i].pitch = 0; } } } else surface_info[i] = {}; } if (std::get<0>(m_rtts.m_bound_depth_stencil)) { if (depth_format == rsx::surface_depth_format::z24s8) __glcheck draw_fbo.depth_stencil = *std::get<1>(m_rtts.m_bound_depth_stencil); else __glcheck draw_fbo.depth = *std::get<1>(m_rtts.m_bound_depth_stencil); const u32 depth_surface_pitch = rsx::method_registers.surface_z_pitch(); std::get<1>(m_rtts.m_bound_depth_stencil)->set_rsx_pitch(rsx::method_registers.surface_z_pitch()); depth_surface_info = { depth_address, depth_surface_pitch, true, surface_format, depth_format, clip_horizontal, clip_vertical }; //Verify pitch given is correct if pitch <= 64 (especially 64) if (depth_surface_pitch <= 64) { const u16 native_pitch = std::get<1>(m_rtts.m_bound_depth_stencil)->get_native_pitch(); if (native_pitch > depth_surface_pitch) { LOG_TRACE(RSX, "Bad depth surface pitch given: surface_width=%d, format=%d, pitch=%d, native_pitch=%d", clip_horizontal, (u32)depth_format, depth_surface_pitch, native_pitch); //Will not transfer this surface between cell and rsx due to misalignment //TODO: Verify correct behaviour depth_surface_info.pitch = 0; } } } else depth_surface_info = {}; framebuffer_status_valid = draw_fbo.check(); if (!framebuffer_status_valid) return; check_zcull_status(true, false); draw_fbo.bind(); set_viewport(); switch (rsx::method_registers.surface_color_target()) { case rsx::surface_target::none: break; case rsx::surface_target::surface_a: __glcheck draw_fbo.draw_buffer(draw_fbo.color[0]); __glcheck draw_fbo.read_buffer(draw_fbo.color[0]); break; case rsx::surface_target::surface_b: __glcheck draw_fbo.draw_buffer(draw_fbo.color[1]); __glcheck draw_fbo.read_buffer(draw_fbo.color[1]); break; case rsx::surface_target::surfaces_a_b: __glcheck draw_fbo.draw_buffers({ draw_fbo.color[0], draw_fbo.color[1] }); __glcheck draw_fbo.read_buffer(draw_fbo.color[0]); break; case rsx::surface_target::surfaces_a_b_c: __glcheck draw_fbo.draw_buffers({ draw_fbo.color[0], draw_fbo.color[1], draw_fbo.color[2] }); __glcheck draw_fbo.read_buffer(draw_fbo.color[0]); break; case rsx::surface_target::surfaces_a_b_c_d: __glcheck draw_fbo.draw_buffers({ draw_fbo.color[0], draw_fbo.color[1], draw_fbo.color[2], draw_fbo.color[3] }); __glcheck draw_fbo.read_buffer(draw_fbo.color[0]); break; } //Mark buffer regions as NO_ACCESS on Cell visible side if (g_cfg.video.write_color_buffers) { auto color_format = rsx::internals::surface_color_format_to_gl(surface_format); for (u8 i = 0; i < rsx::limits::color_buffers_count; ++i) { if (!surface_info[i].address || !surface_info[i].pitch) continue; const u32 range = surface_info[i].pitch * surface_info[i].height; m_gl_texture_cache.lock_rtt_region(surface_info[i].address, range, surface_info[i].width, surface_info[i].height, surface_info[i].pitch, color_format.format, color_format.type, color_format.swap_bytes, *std::get<1>(m_rtts.m_bound_render_targets[i])); } } if (g_cfg.video.write_depth_buffer) { if (depth_surface_info.address && depth_surface_info.pitch) { auto depth_format_gl = rsx::internals::surface_depth_format_to_gl(depth_format); u32 pitch = depth_surface_info.width * 2; if (depth_surface_info.depth_format != rsx::surface_depth_format::z16) pitch *= 2; const u32 range = pitch * depth_surface_info.height; //TODO: Verify that depth surface pitch variance affects results if (pitch != depth_surface_info.pitch) LOG_WARNING(RSX, "Depth surface pitch does not match computed pitch, %d vs %d", depth_surface_info.pitch, pitch); m_gl_texture_cache.lock_rtt_region(depth_surface_info.address, range, depth_surface_info.width, depth_surface_info.height, pitch, depth_format_gl.format, depth_format_gl.type, true, *std::get<1>(m_rtts.m_bound_depth_stencil)); } } }
void GLGSRender::notify_zcull_info_changed() { check_zcull_status(false, false); }