void GLGSRender::check_zcull_status(bool framebuffer_swap, bool force_read) { if (g_cfg.video.disable_zcull_queries) return; bool testing_enabled = zcull_pixel_cnt_enabled || zcull_stats_enabled; if (framebuffer_swap) { zcull_surface_active = false; const u32 zeta_address = depth_surface_info.address; if (zeta_address) { //Find zeta address in bound zculls for (int i = 0; i < rsx::limits::zculls_count; i++) { if (zculls[i].binded) { const u32 rsx_address = rsx::get_address(zculls[i].offset, CELL_GCM_LOCATION_LOCAL); if (rsx_address == zeta_address) { zcull_surface_active = true; break; } } } } } occlusion_query_info* query = nullptr; if (zcull_task_queue.task_stack.size() > 0) query = zcull_task_queue.active_query; if (query && query->active) { if (force_read || (!zcull_rendering_enabled || !testing_enabled || !zcull_surface_active)) { glEndQuery(GL_ANY_SAMPLES_PASSED); query->active = false; query->pending = true; } } else { if (zcull_rendering_enabled && testing_enabled && zcull_surface_active) { //Find query u32 free_index = synchronize_zcull_stats(); query = &occlusion_query_data[free_index]; zcull_task_queue.add(query); glBeginQuery(GL_ANY_SAMPLES_PASSED, query->handle); query->active = true; query->result = 0; query->num_draws = 0; } } }
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; } }
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; } }
u32 GLGSRender::synchronize_zcull_stats(bool hard_sync) { if (!zcull_rendering_enabled || zcull_task_queue.pending == 0) return 0; u32 result = UINT16_MAX; GLint count, status; for (auto &query : zcull_task_queue.task_stack) { if (query == nullptr || query->active) continue; glGetQueryObjectiv(query->handle, GL_QUERY_RESULT_AVAILABLE, &status); if (status == GL_FALSE && !hard_sync) continue; glGetQueryObjectiv(query->handle, GL_QUERY_RESULT, &count); query->pending = false; query = nullptr; current_zcull_stats.zpass_pixel_cnt += count; zcull_task_queue.pending--; } for (u32 i = 0; i < occlusion_query_count; ++i) { auto &query = occlusion_query_data[i]; if (!query.pending && !query.active) { result = i; break; } } if (result == UINT16_MAX && !hard_sync) return synchronize_zcull_stats(true); return result; }