2019-07-28 00:40:10 +02:00
|
|
|
// Copyright 2019 yuzu Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2019-11-28 06:15:34 +01:00
|
|
|
#include <algorithm>
|
2019-11-26 22:52:15 +01:00
|
|
|
#include <cstring>
|
|
|
|
#include <memory>
|
2019-11-28 06:15:34 +01:00
|
|
|
#include <unordered_map>
|
2019-11-26 22:52:15 +01:00
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
|
|
|
|
2019-07-28 00:40:10 +02:00
|
|
|
#include <glad/glad.h>
|
|
|
|
|
2019-11-26 22:52:15 +01:00
|
|
|
#include "common/assert.h"
|
|
|
|
#include "core/core.h"
|
|
|
|
#include "video_core/engines/maxwell_3d.h"
|
|
|
|
#include "video_core/memory_manager.h"
|
2019-07-28 00:40:10 +02:00
|
|
|
#include "video_core/renderer_opengl/gl_query_cache.h"
|
2019-11-26 22:52:15 +01:00
|
|
|
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
2019-07-28 00:40:10 +02:00
|
|
|
|
|
|
|
namespace OpenGL {
|
|
|
|
|
2019-11-26 22:52:15 +01:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
constexpr std::array<GLenum, VideoCore::NumQueryTypes> QueryTargets = {GL_SAMPLES_PASSED};
|
|
|
|
|
2020-02-11 20:02:41 +01:00
|
|
|
constexpr GLenum GetTarget(VideoCore::QueryType type) {
|
2019-11-26 22:52:15 +01:00
|
|
|
return QueryTargets[static_cast<std::size_t>(type)];
|
2019-07-28 00:40:10 +02:00
|
|
|
}
|
|
|
|
|
2019-11-26 22:52:15 +01:00
|
|
|
} // Anonymous namespace
|
|
|
|
|
2020-02-11 20:02:41 +01:00
|
|
|
QueryCache::QueryCache(Core::System& system, RasterizerOpenGL& gl_rasterizer)
|
2020-02-11 22:59:44 +01:00
|
|
|
: VideoCommon::QueryCacheBase<
|
|
|
|
QueryCache, CachedQuery, CounterStream, HostCounter,
|
|
|
|
std::vector<OGLQuery>>{system,
|
|
|
|
static_cast<VideoCore::RasterizerInterface&>(gl_rasterizer)},
|
2020-02-11 20:02:41 +01:00
|
|
|
gl_rasterizer{gl_rasterizer} {}
|
2019-11-26 22:52:15 +01:00
|
|
|
|
|
|
|
QueryCache::~QueryCache() = default;
|
|
|
|
|
2020-02-11 20:02:41 +01:00
|
|
|
OGLQuery QueryCache::AllocateQuery(VideoCore::QueryType type) {
|
2020-02-11 22:59:44 +01:00
|
|
|
auto& reserve = query_pools[static_cast<std::size_t>(type)];
|
2019-11-28 06:15:34 +01:00
|
|
|
OGLQuery query;
|
2019-11-26 22:52:15 +01:00
|
|
|
if (reserve.empty()) {
|
2019-11-28 06:15:34 +01:00
|
|
|
query.Create(GetTarget(type));
|
2020-02-11 20:02:41 +01:00
|
|
|
return query;
|
2019-07-28 00:40:10 +02:00
|
|
|
}
|
|
|
|
|
2020-02-11 20:02:41 +01:00
|
|
|
query = std::move(reserve.back());
|
|
|
|
reserve.pop_back();
|
|
|
|
return query;
|
2019-11-28 06:15:34 +01:00
|
|
|
}
|
|
|
|
|
2020-02-11 20:02:41 +01:00
|
|
|
void QueryCache::Reserve(VideoCore::QueryType type, OGLQuery&& query) {
|
2020-02-11 22:59:44 +01:00
|
|
|
query_pools[static_cast<std::size_t>(type)].push_back(std::move(query));
|
2019-07-28 00:40:10 +02:00
|
|
|
}
|
|
|
|
|
2020-02-11 20:02:41 +01:00
|
|
|
bool QueryCache::AnyCommandQueued() const noexcept {
|
|
|
|
return gl_rasterizer.AnyCommandQueued();
|
2019-11-26 22:52:15 +01:00
|
|
|
}
|
|
|
|
|
2020-02-11 20:02:41 +01:00
|
|
|
HostCounter::HostCounter(QueryCache& cache, std::shared_ptr<HostCounter> dependency,
|
|
|
|
VideoCore::QueryType type)
|
|
|
|
: VideoCommon::HostCounterBase<QueryCache, HostCounter>{std::move(dependency)}, cache{cache},
|
|
|
|
type{type}, query{cache.AllocateQuery(type)} {
|
2019-11-26 22:52:15 +01:00
|
|
|
glBeginQuery(GetTarget(type), query.handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
HostCounter::~HostCounter() {
|
|
|
|
cache.Reserve(type, std::move(query));
|
|
|
|
}
|
|
|
|
|
2020-02-11 20:02:41 +01:00
|
|
|
void HostCounter::EndQuery() {
|
|
|
|
if (!cache.AnyCommandQueued()) {
|
|
|
|
// There are chances a query waited on without commands (glDraw, glClear, glDispatch). Not
|
|
|
|
// having any of these causes a lock. glFlush is considered a command, so we can safely wait
|
|
|
|
// for this. Insert to the OpenGL command stream a flush.
|
|
|
|
glFlush();
|
2019-07-28 00:40:10 +02:00
|
|
|
}
|
2020-02-11 20:02:41 +01:00
|
|
|
glEndQuery(GetTarget(type));
|
2019-11-28 06:15:34 +01:00
|
|
|
}
|
|
|
|
|
2020-02-11 20:02:41 +01:00
|
|
|
u64 HostCounter::BlockingQuery() const {
|
|
|
|
GLint64 value;
|
|
|
|
glGetQueryObjecti64v(query.handle, GL_QUERY_RESULT, &value);
|
|
|
|
return static_cast<u64>(value);
|
2019-11-26 22:52:15 +01:00
|
|
|
}
|
|
|
|
|
2020-02-11 20:02:41 +01:00
|
|
|
CachedQuery::CachedQuery(QueryCache& cache, VideoCore::QueryType type, VAddr cpu_addr, u8* host_ptr)
|
|
|
|
: VideoCommon::CachedQueryBase<HostCounter>{cpu_addr, host_ptr}, cache{&cache}, type{type} {}
|
2019-11-28 06:15:34 +01:00
|
|
|
|
|
|
|
CachedQuery::CachedQuery(CachedQuery&& rhs) noexcept
|
2020-02-11 20:02:41 +01:00
|
|
|
: VideoCommon::CachedQueryBase<HostCounter>(std::move(rhs)), cache{rhs.cache}, type{rhs.type} {}
|
2019-11-26 22:52:15 +01:00
|
|
|
|
2019-11-28 06:15:34 +01:00
|
|
|
CachedQuery& CachedQuery::operator=(CachedQuery&& rhs) noexcept {
|
2020-02-11 20:02:41 +01:00
|
|
|
cache = rhs.cache;
|
2019-11-28 06:15:34 +01:00
|
|
|
type = rhs.type;
|
2020-04-16 04:20:03 +02:00
|
|
|
CachedQueryBase<HostCounter>::operator=(std::move(rhs));
|
2019-11-28 06:15:34 +01:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2019-11-26 22:52:15 +01:00
|
|
|
void CachedQuery::Flush() {
|
2020-02-11 20:02:41 +01:00
|
|
|
// Waiting for a query while another query of the same target is enabled locks Nvidia's driver.
|
|
|
|
// To avoid this disable and re-enable keeping the dependency stream.
|
|
|
|
// But we only have to do this if we have pending waits to be done.
|
|
|
|
auto& stream = cache->Stream(type);
|
|
|
|
const bool slice_counter = WaitPending() && stream.IsEnabled();
|
|
|
|
if (slice_counter) {
|
|
|
|
stream.Update(false);
|
2019-11-28 06:15:34 +01:00
|
|
|
}
|
2019-11-26 22:52:15 +01:00
|
|
|
|
2020-02-11 20:02:41 +01:00
|
|
|
VideoCommon::CachedQueryBase<HostCounter>::Flush();
|
2019-07-28 00:40:10 +02:00
|
|
|
|
2020-02-11 20:02:41 +01:00
|
|
|
if (slice_counter) {
|
|
|
|
stream.Update(true);
|
|
|
|
}
|
2019-11-28 06:15:34 +01:00
|
|
|
}
|
|
|
|
|
2019-07-28 00:40:10 +02:00
|
|
|
} // namespace OpenGL
|