mirror of
https://github.com/Awakenchan/LanternEngine.git
synced 2026-11-10 01:11:45 -10:00
328 lines
10 KiB
C++
328 lines
10 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <initializer_list>
|
|
#include <vector>
|
|
|
|
#include "gpu/shadps4/video_core/renderer_vulkan/occlusion_model.h"
|
|
|
|
using namespace OcclusionModel;
|
|
|
|
namespace {
|
|
constexpr std::uint32_t Native = 1u << 16;
|
|
|
|
struct Pipe {
|
|
std::uint64_t budget = 64;
|
|
std::uint64_t issued = 0;
|
|
std::uint64_t next_query = 0;
|
|
std::uint64_t frame = 0;
|
|
std::vector<std::uint64_t> samples;
|
|
OpenBlocks open;
|
|
|
|
void Draw(std::uint64_t count, bool dropped = false) {
|
|
++issued;
|
|
if (dropped || !open.WantsQuery(next_query, budget)) {
|
|
return;
|
|
}
|
|
samples.push_back(count);
|
|
++next_query;
|
|
}
|
|
void Begin(std::uint64_t block) {
|
|
open.Begin(block, issued, next_query, frame);
|
|
}
|
|
std::uint64_t End(std::uint64_t block) {
|
|
const auto closed = open.End(block, issued, next_query);
|
|
if (!closed || !closed->complete) {
|
|
return PlainlyVisible;
|
|
}
|
|
std::uint64_t sum = 0;
|
|
for (std::uint64_t q = closed->first_query; q < closed->first_query + closed->queries;
|
|
++q) {
|
|
sum += samples[q];
|
|
}
|
|
return sum;
|
|
}
|
|
};
|
|
|
|
std::uint64_t Passed(const std::uint64_t* words, std::uint32_t dbs) {
|
|
std::uint64_t sum = 0;
|
|
for (std::uint32_t db = 0; db < dbs; ++db) {
|
|
sum += (words[2 * db + 1] & ~ValidBit) - (words[2 * db] & ~ValidBit);
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
void BlockWords() {
|
|
for (const std::uint32_t dbs : {1u, 8u, 16u}) {
|
|
for (std::uint64_t count = 0; count < 300; ++count) {
|
|
std::uint64_t sum = 0;
|
|
for (std::uint32_t db = 0; db < dbs; ++db) {
|
|
sum += DbPart(count, dbs, db);
|
|
assert(DbPart(count + 1, dbs, db) >= DbPart(count, dbs, db));
|
|
}
|
|
assert(sum == count);
|
|
}
|
|
for (const std::uint64_t base : {0ull, 5ull, 987654321ull}) {
|
|
for (const std::uint64_t samples : std::initializer_list<std::uint64_t>{0, 1, 7, 5000, PlainlyVisible}) {
|
|
std::uint64_t words[2 * MaxDbs] = {};
|
|
assert(ReadAnswer(words, dbs) == Answer::Pending);
|
|
FillBlock(words, dbs, base, samples);
|
|
assert(Passed(words, dbs) == samples);
|
|
assert(ReadAnswer(words, dbs) == (samples ? Answer::Seen : Answer::Hidden));
|
|
std::uint64_t half[2 * MaxDbs] = {};
|
|
for (std::uint32_t db = 0; db < dbs; ++db) {
|
|
half[2 * db] = words[2 * db];
|
|
}
|
|
assert(ReadAnswer(half, dbs) == Answer::Pending);
|
|
half[2 * (dbs - 1) + 1] = 0;
|
|
for (std::uint32_t db = 0; db + 1 < dbs; ++db) {
|
|
half[2 * db + 1] = words[2 * db + 1];
|
|
}
|
|
assert(ReadAnswer(half, dbs) == Answer::Pending);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void QueryCounts() {
|
|
assert(QueryCount(0, false, true, Native) == PlainlyVisible);
|
|
assert(QueryCount(0, false, false, Native) == PlainlyVisible);
|
|
assert(QueryCount(1, true, false, Native) == PlainlyVisible);
|
|
assert(QueryCount(0, true, false, Native) == 0);
|
|
assert(QueryCount(0, true, true, 4 * Native) == 0);
|
|
assert(QueryCount(10, true, true, Native) == 10);
|
|
assert(QueryCount(1, true, true, Native + 1) == 2);
|
|
|
|
assert(ScaleToNative(1920, 1080) == Native);
|
|
assert(ScaleToNative(2560, 1440) == Native);
|
|
assert(ScaleToNative(960, 540) == 4 * Native);
|
|
assert(ScaleToNative(0, 0) == Native);
|
|
assert(QueryCount(250, true, true, ScaleToNative(960, 540)) == 1000);
|
|
}
|
|
|
|
void Predication() {
|
|
assert(DrawPredicated(false, true, true));
|
|
assert(DrawPredicated(true, true, false));
|
|
assert(DrawPredicated(true, false, true));
|
|
assert(!DrawPredicated(false, false, true));
|
|
assert(DrawPredicated(false, false, false));
|
|
assert(!DrawPredicated(true, false, false));
|
|
}
|
|
|
|
void ConservativeVisibility() {
|
|
assert(QueryFresh(100, 100, 6));
|
|
assert(QueryFresh(100, 106, 6));
|
|
assert(!QueryFresh(100, 107, 6));
|
|
assert(!QueryFresh(100, 0, 6));
|
|
assert(VisibilityCount(0, 1, true, true) == 0);
|
|
assert(VisibilityCount(0, 64, true, true) == 0);
|
|
for (const std::uint64_t samples : std::initializer_list<std::uint64_t>{1, 2, 10, 1000, PlainlyVisible}) {
|
|
assert(VisibilityCount(samples, 1, true, true) == PlainlyVisible);
|
|
}
|
|
assert(VisibilityCount(0, 0, true, true) == PlainlyVisible);
|
|
assert(VisibilityCount(0, 1, false, true) == PlainlyVisible);
|
|
assert(VisibilityCount(0, 1, true, false) == PlainlyVisible);
|
|
SteadyCount history;
|
|
for (unsigned i = 0; i < SteadyCount::Window; ++i) {
|
|
history.Add(0);
|
|
}
|
|
assert(history.Add(VisibilityCount(1, 1, true, true)) == PlainlyVisible);
|
|
for (unsigned i = 0; i + 1 < SteadyCount::Window; ++i) {
|
|
assert(history.Add(0) == PlainlyVisible);
|
|
}
|
|
assert(history.Add(0) == 0);
|
|
}
|
|
|
|
void LateAnswers() {
|
|
assert(LateAnswerWritable(100, 106, 6, false));
|
|
assert(!LateAnswerWritable(100, 107, 6, false));
|
|
assert(LateAnswerWritable(100, 112, 6, true));
|
|
assert(!LateAnswerWritable(100, 113, 6, true));
|
|
assert(!LateAnswerWritable(100, 0, 6, true));
|
|
}
|
|
|
|
void Steadying() {
|
|
{
|
|
SteadyCount fresh;
|
|
for (std::uint32_t i = 0; i + 1 < SteadyCount::Window; ++i) {
|
|
assert(fresh.Add(0) == SteadyCount::Unseen);
|
|
}
|
|
assert(fresh.Add(0) == 0);
|
|
assert(fresh.Add(9) == 9);
|
|
for (std::uint32_t i = 0; i + 1 < SteadyCount::Window; ++i) {
|
|
assert(fresh.Add(0) == 9);
|
|
}
|
|
assert(fresh.Add(0) == 0);
|
|
}
|
|
{
|
|
SteadyCount lamp;
|
|
for (const std::uint64_t m : {40ull, 0ull, 35ull, 0ull, 0ull, 41ull, 0ull, 38ull}) {
|
|
assert(lamp.Add(m) >= 35);
|
|
}
|
|
SteadyCount fading;
|
|
for (std::uint32_t i = 0; i < SteadyCount::Window; ++i) {
|
|
fading.Add(100);
|
|
}
|
|
for (std::uint32_t i = 0; i + 1 < SteadyCount::Window; ++i) {
|
|
assert(fading.Add(10) == 100);
|
|
}
|
|
assert(fading.Add(10) == 10);
|
|
SteadyCount unknown;
|
|
unknown.Add(0);
|
|
assert(unknown.Add(PlainlyVisible) == PlainlyVisible);
|
|
assert(unknown.Add(0) == PlainlyVisible);
|
|
}
|
|
}
|
|
|
|
void Measuring() {
|
|
const std::uint64_t a = 0x1000, b = 0x2000;
|
|
{
|
|
Pipe pipe;
|
|
pipe.Draw(500);
|
|
assert(pipe.next_query == 0);
|
|
pipe.Begin(a);
|
|
pipe.Draw(0);
|
|
assert(pipe.End(a) == 0);
|
|
pipe.Draw(500);
|
|
pipe.Begin(a);
|
|
pipe.Draw(12);
|
|
assert(pipe.End(a) == 12);
|
|
assert(pipe.next_query == 2);
|
|
assert(pipe.open.Empty());
|
|
}
|
|
{
|
|
Pipe pipe;
|
|
pipe.Begin(a);
|
|
pipe.Draw(0);
|
|
pipe.Begin(b);
|
|
pipe.Draw(0);
|
|
assert(pipe.End(b) == 0);
|
|
pipe.Draw(0);
|
|
pipe.Draw(0);
|
|
assert(pipe.End(a) == 0);
|
|
pipe.Begin(a);
|
|
pipe.Begin(b);
|
|
pipe.Draw(3);
|
|
assert(pipe.End(b) == 3);
|
|
pipe.Draw(0);
|
|
assert(pipe.End(a) == 3);
|
|
}
|
|
{
|
|
Pipe pipe;
|
|
pipe.Begin(a);
|
|
pipe.Draw(1);
|
|
pipe.Begin(b);
|
|
pipe.Draw(0);
|
|
assert(pipe.End(a) == 1);
|
|
pipe.Draw(4);
|
|
assert(pipe.End(b) == 4);
|
|
}
|
|
{
|
|
Pipe pipe;
|
|
pipe.budget = 3;
|
|
pipe.Begin(a);
|
|
for (int i = 0; i < 3; ++i) {
|
|
pipe.Draw(0);
|
|
}
|
|
assert(pipe.End(a) == 0);
|
|
pipe.Begin(a);
|
|
for (int i = 0; i < 4; ++i) {
|
|
pipe.Draw(0);
|
|
}
|
|
assert(pipe.End(a) == PlainlyVisible);
|
|
pipe.Begin(a);
|
|
for (int i = 0; i < 3; ++i) {
|
|
pipe.Draw(0);
|
|
}
|
|
assert(!pipe.open.WantsQuery(pipe.next_query, pipe.budget));
|
|
pipe.Begin(b);
|
|
assert(pipe.open.WantsQuery(pipe.next_query, pipe.budget));
|
|
pipe.Draw(0);
|
|
assert(pipe.End(b) == 0);
|
|
assert(pipe.End(a) == 0);
|
|
}
|
|
{
|
|
Pipe pipe;
|
|
pipe.Begin(a);
|
|
pipe.Draw(0);
|
|
pipe.Draw(0, true);
|
|
assert(pipe.End(a) == PlainlyVisible);
|
|
assert(pipe.End(b) == PlainlyVisible);
|
|
pipe.Begin(a);
|
|
pipe.Draw(9);
|
|
pipe.Begin(a);
|
|
pipe.Draw(0);
|
|
assert(pipe.End(a) == 0);
|
|
assert(pipe.open.Empty());
|
|
}
|
|
{
|
|
Pipe pipe;
|
|
assert(pipe.open.FirstNeeded(pipe.next_query) == 0);
|
|
pipe.Begin(a);
|
|
pipe.Draw(1);
|
|
pipe.Begin(b);
|
|
pipe.Draw(1);
|
|
assert(pipe.open.FirstNeeded(pipe.next_query) == 0);
|
|
pipe.End(a);
|
|
assert(pipe.open.FirstNeeded(pipe.next_query) == 1);
|
|
pipe.End(b);
|
|
assert(pipe.open.FirstNeeded(pipe.next_query) == 2);
|
|
pipe.Begin(a);
|
|
pipe.Draw(1);
|
|
pipe.frame = 10;
|
|
pipe.open.Expire(pipe.frame, 8);
|
|
assert(pipe.open.Empty());
|
|
assert(pipe.open.FirstNeeded(pipe.next_query) == 3);
|
|
assert(pipe.End(a) == PlainlyVisible);
|
|
pipe.Begin(a);
|
|
pipe.frame = 18;
|
|
pipe.open.Expire(pipe.frame, 8);
|
|
assert(pipe.open.Size() == 1);
|
|
}
|
|
{
|
|
Pipe pipe;
|
|
for (std::uint64_t i = 0; i <= OpenBlocks::Capacity; ++i) {
|
|
pipe.Begin(0x10000 + 16 * i);
|
|
}
|
|
assert(pipe.open.Size() == OpenBlocks::Capacity);
|
|
pipe.Draw(0);
|
|
assert(pipe.End(0x10000) == PlainlyVisible);
|
|
assert(pipe.End(0x10000 + 16 * OpenBlocks::Capacity) == 0);
|
|
}
|
|
}
|
|
|
|
void Answers() {
|
|
for (const std::uint32_t dbs : {8u, 16u}) {
|
|
SteadyCount steady;
|
|
std::uint64_t counter = 0;
|
|
const std::uint64_t measured[] = {12, 0, 0, 0, 0, 0, 5, PlainlyVisible, 0};
|
|
const Answer expected[] = {Answer::Seen, Answer::Seen, Answer::Seen,
|
|
Answer::Seen, Answer::Seen, Answer::Hidden,
|
|
Answer::Seen, Answer::Seen, Answer::Seen};
|
|
for (std::size_t i = 0; i < sizeof(measured) / sizeof(measured[0]); ++i) {
|
|
const std::uint64_t report = steady.Add(measured[i]);
|
|
std::uint64_t words[2 * MaxDbs] = {};
|
|
FillBlock(words, dbs, counter, report);
|
|
counter += report;
|
|
assert(Passed(words, dbs) == report);
|
|
assert(ReadAnswer(words, dbs) == expected[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
int main() {
|
|
BlockWords();
|
|
QueryCounts();
|
|
Predication();
|
|
ConservativeVisibility();
|
|
LateAnswers();
|
|
Steadying();
|
|
Measuring();
|
|
Answers();
|
|
std::printf("occlusion model: ok\n");
|
|
return 0;
|
|
}
|