2014-09-14 16:52:51 +00:00
|
|
|
// Copyright 2014 Dolphin Emulator Project
|
2021-07-05 01:22:19 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2014-09-14 16:52:51 +00:00
|
|
|
|
|
|
|
#include "VideoCommon/BoundingBox.h"
|
2019-12-05 15:58:03 +00:00
|
|
|
|
2021-10-09 23:48:23 +00:00
|
|
|
#include <algorithm>
|
|
|
|
|
2021-06-09 11:42:21 +00:00
|
|
|
#include "Common/Assert.h"
|
2015-09-24 07:19:43 +00:00
|
|
|
#include "Common/ChunkFile.h"
|
|
|
|
#include "Common/CommonTypes.h"
|
2019-12-05 16:55:21 +00:00
|
|
|
#include "VideoCommon/PixelShaderManager.h"
|
2021-06-09 11:42:21 +00:00
|
|
|
#include "VideoCommon/VideoConfig.h"
|
2014-09-14 16:52:51 +00:00
|
|
|
|
2021-10-09 23:47:06 +00:00
|
|
|
#include <algorithm>
|
|
|
|
|
2023-01-27 00:21:09 +00:00
|
|
|
std::unique_ptr<BoundingBox> g_bounding_box;
|
|
|
|
|
2022-12-27 16:42:02 +00:00
|
|
|
void BoundingBox::Enable(PixelShaderManager& pixel_shader_manager)
|
2019-12-05 15:58:03 +00:00
|
|
|
{
|
2021-06-09 11:42:21 +00:00
|
|
|
m_is_active = true;
|
2022-12-27 16:42:02 +00:00
|
|
|
pixel_shader_manager.SetBoundingBoxActive(m_is_active);
|
2019-12-05 15:58:03 +00:00
|
|
|
}
|
|
|
|
|
2022-12-27 16:42:02 +00:00
|
|
|
void BoundingBox::Disable(PixelShaderManager& pixel_shader_manager)
|
2019-12-05 15:58:03 +00:00
|
|
|
{
|
2021-06-09 11:42:21 +00:00
|
|
|
m_is_active = false;
|
2022-12-27 16:42:02 +00:00
|
|
|
pixel_shader_manager.SetBoundingBoxActive(m_is_active);
|
2019-12-05 15:58:03 +00:00
|
|
|
}
|
|
|
|
|
2021-06-09 11:42:21 +00:00
|
|
|
void BoundingBox::Flush()
|
2019-12-05 15:58:03 +00:00
|
|
|
{
|
2023-01-29 14:40:15 +00:00
|
|
|
if (!g_ActiveConfig.bBBoxEnable || !g_ActiveConfig.backend_info.bSupportsBBox)
|
2021-06-09 11:42:21 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
m_is_valid = false;
|
|
|
|
|
|
|
|
if (std::none_of(m_dirty.begin(), m_dirty.end(), [](bool dirty) { return dirty; }))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// TODO: Does this make any difference over just writing all the values?
|
|
|
|
// Games only ever seem to write all 4 values at once anyways.
|
|
|
|
for (u32 start = 0; start < NUM_BBOX_VALUES; ++start)
|
|
|
|
{
|
|
|
|
if (!m_dirty[start])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
u32 end = start + 1;
|
|
|
|
while (end < NUM_BBOX_VALUES && m_dirty[end])
|
|
|
|
++end;
|
|
|
|
|
|
|
|
for (u32 i = start; i < end; ++i)
|
|
|
|
m_dirty[i] = false;
|
|
|
|
|
2023-12-09 19:54:17 +00:00
|
|
|
Write(start, std::span(m_values.begin() + start, m_values.begin() + end));
|
2021-06-09 11:42:21 +00:00
|
|
|
}
|
2019-12-05 15:58:03 +00:00
|
|
|
}
|
|
|
|
|
2021-06-09 11:42:21 +00:00
|
|
|
void BoundingBox::Readback()
|
2019-12-05 15:58:03 +00:00
|
|
|
{
|
2021-06-09 11:42:21 +00:00
|
|
|
if (!g_ActiveConfig.backend_info.bSupportsBBox)
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto read_values = Read(0, NUM_BBOX_VALUES);
|
|
|
|
|
|
|
|
// Preserve dirty values, that way we don't need to sync.
|
|
|
|
for (u32 i = 0; i < NUM_BBOX_VALUES; i++)
|
|
|
|
{
|
|
|
|
if (!m_dirty[i])
|
|
|
|
m_values[i] = read_values[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
m_is_valid = true;
|
2019-12-05 15:58:03 +00:00
|
|
|
}
|
|
|
|
|
2021-06-09 11:42:21 +00:00
|
|
|
u16 BoundingBox::Get(u32 index)
|
2019-12-05 15:58:03 +00:00
|
|
|
{
|
2021-06-09 11:42:21 +00:00
|
|
|
ASSERT(index < NUM_BBOX_VALUES);
|
|
|
|
|
2023-01-29 14:40:15 +00:00
|
|
|
if (!g_ActiveConfig.bBBoxEnable || !g_ActiveConfig.backend_info.bSupportsBBox)
|
|
|
|
return m_bounding_box_fallback[index];
|
|
|
|
|
2021-06-09 11:42:21 +00:00
|
|
|
if (!m_is_valid)
|
|
|
|
Readback();
|
|
|
|
|
|
|
|
return static_cast<u16>(m_values[index]);
|
2019-12-05 15:58:03 +00:00
|
|
|
}
|
|
|
|
|
2021-06-09 11:42:21 +00:00
|
|
|
void BoundingBox::Set(u32 index, u16 value)
|
2019-12-05 15:58:03 +00:00
|
|
|
{
|
2021-06-09 11:42:21 +00:00
|
|
|
ASSERT(index < NUM_BBOX_VALUES);
|
|
|
|
|
2023-01-29 14:40:15 +00:00
|
|
|
if (!g_ActiveConfig.bBBoxEnable || !g_ActiveConfig.backend_info.bSupportsBBox)
|
|
|
|
{
|
|
|
|
m_bounding_box_fallback[index] = value;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-06-09 11:42:21 +00:00
|
|
|
if (m_is_valid && m_values[index] == value)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_values[index] = value;
|
|
|
|
m_dirty[index] = true;
|
2019-12-05 15:58:03 +00:00
|
|
|
}
|
2014-09-14 16:52:51 +00:00
|
|
|
|
2021-06-09 11:42:21 +00:00
|
|
|
// FIXME: This may not work correctly if we're in the middle of a draw.
|
|
|
|
// We should probably ensure that state saves only happen on frame boundaries.
|
|
|
|
// Nonetheless, it has been designed to be as safe as possible.
|
|
|
|
void BoundingBox::DoState(PointerWrap& p)
|
2014-09-14 16:52:51 +00:00
|
|
|
{
|
2023-01-29 14:40:15 +00:00
|
|
|
p.DoArray(m_bounding_box_fallback);
|
2021-06-09 11:42:21 +00:00
|
|
|
p.Do(m_is_active);
|
|
|
|
p.DoArray(m_values);
|
|
|
|
p.DoArray(m_dirty);
|
|
|
|
p.Do(m_is_valid);
|
|
|
|
|
|
|
|
// We handle saving the backend values specially rather than using Readback() and Flush() so that
|
|
|
|
// we don't mess up the current cache state
|
|
|
|
std::vector<BBoxType> backend_values(NUM_BBOX_VALUES);
|
2022-05-18 05:29:05 +00:00
|
|
|
if (p.IsReadMode())
|
2021-06-09 11:42:21 +00:00
|
|
|
{
|
|
|
|
p.Do(backend_values);
|
2014-09-14 16:52:51 +00:00
|
|
|
|
2021-06-09 11:42:21 +00:00
|
|
|
if (g_ActiveConfig.backend_info.bSupportsBBox)
|
|
|
|
Write(0, backend_values);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (g_ActiveConfig.backend_info.bSupportsBBox)
|
|
|
|
backend_values = Read(0, NUM_BBOX_VALUES);
|
|
|
|
|
|
|
|
p.Do(backend_values);
|
|
|
|
}
|
|
|
|
}
|