early-access version 1857
This commit is contained in:
parent
c73b4b3ce7
commit
28b8f1ac43
7 changed files with 69 additions and 158 deletions
|
@ -1,7 +1,7 @@
|
|||
yuzu emulator early access
|
||||
=============
|
||||
|
||||
This is the source code for early-access 1855.
|
||||
This is the source code for early-access 1857.
|
||||
|
||||
## Legal Notice
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ public:
|
|||
{
|
||||
std::unique_lock lock{queue_mutex};
|
||||
requests.emplace(std::move(work));
|
||||
++work_scherduled;
|
||||
++work_scheduled;
|
||||
}
|
||||
condition.notify_one();
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ public:
|
|||
});
|
||||
std::unique_lock lock{queue_mutex};
|
||||
wait_condition.wait(lock, [this] {
|
||||
return workers_stopped >= workers_queued || work_done >= work_scherduled;
|
||||
return workers_stopped >= workers_queued || work_done >= work_scheduled;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ private:
|
|||
std::mutex queue_mutex;
|
||||
std::condition_variable_any condition;
|
||||
std::condition_variable wait_condition;
|
||||
std::atomic<size_t> work_scherduled{};
|
||||
std::atomic<size_t> work_scheduled{};
|
||||
std::atomic<size_t> work_done{};
|
||||
std::atomic<size_t> workers_stopped{};
|
||||
std::atomic<size_t> workers_queued{};
|
||||
|
|
|
@ -14,7 +14,7 @@ class UniqueFunction {
|
|||
class CallableBase {
|
||||
public:
|
||||
virtual ~CallableBase() = default;
|
||||
virtual ResultType operator()(Args...) = 0;
|
||||
virtual ResultType operator()(Args&&...) = 0;
|
||||
};
|
||||
|
||||
template <typename Functor>
|
||||
|
@ -23,7 +23,7 @@ class UniqueFunction {
|
|||
Callable(Functor&& functor_) : functor{std::move(functor_)} {}
|
||||
~Callable() override = default;
|
||||
|
||||
ResultType operator()(Args... args) override {
|
||||
ResultType operator()(Args&&... args) override {
|
||||
return functor(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
|
@ -38,25 +38,20 @@ public:
|
|||
UniqueFunction(Functor&& functor)
|
||||
: callable{std::make_unique<Callable<Functor>>(std::move(functor))} {}
|
||||
|
||||
UniqueFunction& operator=(UniqueFunction<ResultType, Args...>&& rhs) noexcept {
|
||||
callable = std::move(rhs.callable);
|
||||
return *this;
|
||||
}
|
||||
UniqueFunction& operator=(UniqueFunction&& rhs) noexcept = default;
|
||||
UniqueFunction(UniqueFunction&& rhs) noexcept = default;
|
||||
|
||||
UniqueFunction(UniqueFunction<ResultType, Args...>&& rhs) noexcept
|
||||
: callable{std::move(rhs.callable)} {}
|
||||
UniqueFunction& operator=(const UniqueFunction&) = delete;
|
||||
UniqueFunction(const UniqueFunction&) = delete;
|
||||
|
||||
ResultType operator()(Args... args) const {
|
||||
ResultType operator()(Args&&... args) const {
|
||||
return (*callable)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
return callable != nullptr;
|
||||
return static_cast<bool>(callable);
|
||||
}
|
||||
|
||||
UniqueFunction& operator=(const UniqueFunction<ResultType, Args...>&) = delete;
|
||||
UniqueFunction(const UniqueFunction<ResultType, Args...>&) = delete;
|
||||
|
||||
private:
|
||||
std::unique_ptr<CallableBase> callable;
|
||||
};
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
#include "video_core/engines/fermi_2d.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/surface.h"
|
||||
|
||||
using VideoCore::Surface::BytesPerBlock;
|
||||
using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
|
||||
|
||||
namespace Tegra::Engines {
|
||||
|
||||
|
@ -49,7 +53,7 @@ void Fermi2D::Blit() {
|
|||
UNIMPLEMENTED_IF_MSG(regs.clip_enable != 0, "Clipped blit enabled");
|
||||
|
||||
const auto& args = regs.pixels_from_memory;
|
||||
const Config config{
|
||||
Config config{
|
||||
.operation = regs.operation,
|
||||
.filter = args.sample_mode.filter,
|
||||
.dst_x0 = args.dst_x0,
|
||||
|
@ -61,7 +65,21 @@ void Fermi2D::Blit() {
|
|||
.src_x1 = static_cast<s32>((args.du_dx * args.dst_width + args.src_x0) >> 32),
|
||||
.src_y1 = static_cast<s32>((args.dv_dy * args.dst_height + args.src_y0) >> 32),
|
||||
};
|
||||
if (!rasterizer->AccelerateSurfaceCopy(regs.src, regs.dst, config)) {
|
||||
Surface src = regs.src;
|
||||
const auto bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format));
|
||||
const auto need_align_to_pitch =
|
||||
src.linear == Tegra::Engines::Fermi2D::MemoryLayout::Pitch &&
|
||||
static_cast<s32>(src.width) == config.src_x1 &&
|
||||
config.src_x1 > static_cast<s32>(src.pitch / bytes_per_pixel) && config.src_x0 > 0;
|
||||
if (need_align_to_pitch) {
|
||||
auto address = src.Address() + config.src_x0 * bytes_per_pixel;
|
||||
src.addr_upper = static_cast<u32>(address >> 32);
|
||||
src.addr_lower = static_cast<u32>(address);
|
||||
src.width -= config.src_x0;
|
||||
config.src_x1 -= config.src_x0;
|
||||
config.src_x0 = 0;
|
||||
}
|
||||
if (!rasterizer->AccelerateSurfaceCopy(src, regs.dst, config)) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -261,9 +261,9 @@ void UtilShaders::CopyBC4(Image& dst_image, Image& src_image, std::span<const Im
|
|||
glUniform3ui(LOC_SRC_OFFSET, copy.src_offset.x, copy.src_offset.y, copy.src_offset.z);
|
||||
glUniform3ui(LOC_DST_OFFSET, copy.dst_offset.x, copy.dst_offset.y, copy.dst_offset.z);
|
||||
glBindImageTexture(BINDING_INPUT_IMAGE, src_image.StorageHandle(),
|
||||
copy.src_subresource.base_level, GL_FALSE, 0, GL_READ_ONLY, GL_RG32UI);
|
||||
copy.src_subresource.base_level, GL_TRUE, 0, GL_READ_ONLY, GL_RG32UI);
|
||||
glBindImageTexture(BINDING_OUTPUT_IMAGE, dst_image.StorageHandle(),
|
||||
copy.dst_subresource.base_level, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8UI);
|
||||
copy.dst_subresource.base_level, GL_TRUE, 0, GL_WRITE_ONLY, GL_RGBA8UI);
|
||||
glDispatchCompute(copy.extent.width, copy.extent.height, copy.extent.depth);
|
||||
}
|
||||
program_manager.RestoreGuestCompute();
|
||||
|
|
|
@ -159,9 +159,7 @@ public:
|
|||
/// Blit an image with the given parameters
|
||||
void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
|
||||
const Tegra::Engines::Fermi2D::Surface& src,
|
||||
const Tegra::Engines::Fermi2D::Config& copy,
|
||||
std::optional<Region2D> src_region_override = {},
|
||||
std::optional<Region2D> dst_region_override = {});
|
||||
const Tegra::Engines::Fermi2D::Config& copy);
|
||||
|
||||
/// Invalidate the contents of the color buffer index
|
||||
/// These contents become unspecified, the cache can assume aggressive optimizations.
|
||||
|
@ -760,9 +758,7 @@ void TextureCache<P>::UnmapGPUMemory(GPUVAddr gpu_addr, size_t size) {
|
|||
template <class P>
|
||||
void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
|
||||
const Tegra::Engines::Fermi2D::Surface& src,
|
||||
const Tegra::Engines::Fermi2D::Config& copy,
|
||||
std::optional<Region2D> src_override,
|
||||
std::optional<Region2D> dst_override) {
|
||||
const Tegra::Engines::Fermi2D::Config& copy) {
|
||||
const BlitImages images = GetBlitImages(dst, src);
|
||||
const ImageId dst_id = images.dst_id;
|
||||
const ImageId src_id = images.src_id;
|
||||
|
@ -773,47 +769,25 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
|
|||
const ImageBase& src_image = slot_images[src_id];
|
||||
|
||||
// TODO: Deduplicate
|
||||
const std::optional dst_base = dst_image.TryFindBase(dst.Address());
|
||||
const SubresourceRange dst_range{.base = dst_base.value(), .extent = {1, 1}};
|
||||
const ImageViewInfo dst_view_info(ImageViewType::e2D, images.dst_format, dst_range);
|
||||
const auto [dst_framebuffer_id, dst_view_id] = RenderTargetFromImage(dst_id, dst_view_info);
|
||||
const auto [src_samples_x, src_samples_y] = SamplesLog2(src_image.info.num_samples);
|
||||
|
||||
// out of bounds texture blit checking
|
||||
const bool use_override = src_override.has_value();
|
||||
const s32 src_x0 = copy.src_x0 >> src_samples_x;
|
||||
s32 src_x1 = use_override ? src_override->end.x : copy.src_x1 >> src_samples_x;
|
||||
const s32 src_y0 = copy.src_y0 >> src_samples_y;
|
||||
const s32 src_y1 = copy.src_y1 >> src_samples_y;
|
||||
|
||||
const auto src_width = static_cast<s32>(src_image.info.size.width);
|
||||
const bool width_oob = src_x1 > src_width;
|
||||
const auto width_diff = width_oob ? src_x1 - src_width : 0;
|
||||
if (width_oob) {
|
||||
src_x1 = src_width;
|
||||
}
|
||||
|
||||
const Region2D src_dimensions{
|
||||
Offset2D{.x = src_x0, .y = src_y0},
|
||||
Offset2D{.x = src_x1, .y = src_y1},
|
||||
};
|
||||
const auto src_region = use_override ? *src_override : src_dimensions;
|
||||
|
||||
const std::optional src_base = src_image.TryFindBase(src.Address());
|
||||
const SubresourceRange src_range{.base = src_base.value(), .extent = {1, 1}};
|
||||
const ImageViewInfo src_view_info(ImageViewType::e2D, images.src_format, src_range);
|
||||
const auto [src_framebuffer_id, src_view_id] = RenderTargetFromImage(src_id, src_view_info);
|
||||
const auto [dst_samples_x, dst_samples_y] = SamplesLog2(dst_image.info.num_samples);
|
||||
|
||||
const s32 dst_x0 = copy.dst_x0 >> dst_samples_x;
|
||||
const s32 dst_x1 = copy.dst_x1 >> dst_samples_x;
|
||||
const s32 dst_y0 = copy.dst_y0 >> dst_samples_y;
|
||||
const s32 dst_y1 = copy.dst_y1 >> dst_samples_y;
|
||||
const Region2D dst_dimensions{
|
||||
Offset2D{.x = dst_x0, .y = dst_y0},
|
||||
Offset2D{.x = dst_x1 - width_diff, .y = dst_y1},
|
||||
const auto [src_samples_x, src_samples_y] = SamplesLog2(src_image.info.num_samples);
|
||||
const Region2D src_region{
|
||||
Offset2D{.x = copy.src_x0 >> src_samples_x, .y = copy.src_y0 >> src_samples_y},
|
||||
Offset2D{.x = copy.src_x1 >> src_samples_x, .y = copy.src_y1 >> src_samples_y},
|
||||
};
|
||||
|
||||
const std::optional dst_base = dst_image.TryFindBase(dst.Address());
|
||||
const SubresourceRange dst_range{.base = dst_base.value(), .extent = {1, 1}};
|
||||
const ImageViewInfo dst_view_info(ImageViewType::e2D, images.dst_format, dst_range);
|
||||
const auto [dst_framebuffer_id, dst_view_id] = RenderTargetFromImage(dst_id, dst_view_info);
|
||||
const auto [dst_samples_x, dst_samples_y] = SamplesLog2(dst_image.info.num_samples);
|
||||
const Region2D dst_region{
|
||||
Offset2D{.x = copy.dst_x0 >> dst_samples_x, .y = copy.dst_y0 >> dst_samples_y},
|
||||
Offset2D{.x = copy.dst_x1 >> dst_samples_x, .y = copy.dst_y1 >> dst_samples_y},
|
||||
};
|
||||
const auto dst_region = use_override ? *dst_override : dst_dimensions;
|
||||
|
||||
// Always call this after src_framebuffer_id was queried, as the address might be invalidated.
|
||||
Framebuffer* const dst_framebuffer = &slot_framebuffers[dst_framebuffer_id];
|
||||
|
@ -830,21 +804,6 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
|
|||
runtime.BlitImage(dst_framebuffer, dst_view, src_view, dst_region, src_region, copy.filter,
|
||||
copy.operation);
|
||||
}
|
||||
|
||||
if (width_oob) {
|
||||
// Continue copy of the oob region of the texture on the next row
|
||||
auto oob_src = src;
|
||||
oob_src.height++;
|
||||
const Region2D src_region_override{
|
||||
Offset2D{.x = 0, .y = src_y0 + 1},
|
||||
Offset2D{.x = width_diff, .y = src_y1 + 1},
|
||||
};
|
||||
const Region2D dst_region_override{
|
||||
Offset2D{.x = dst_x1 - width_diff, .y = dst_y0},
|
||||
Offset2D{.x = dst_x1, .y = dst_y1},
|
||||
};
|
||||
BlitImage(dst, oob_src, copy, src_region_override, dst_region_override);
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
|
|
|
@ -18,15 +18,11 @@
|
|||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#if __cpp_lib_parallel_algorithm
|
||||
#include <execution>
|
||||
#endif
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/container/static_vector.hpp>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/textures/astc.h"
|
||||
|
||||
|
@ -1554,87 +1550,30 @@ static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth,
|
|||
|
||||
void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
|
||||
uint32_t block_width, uint32_t block_height, std::span<uint8_t> output) {
|
||||
struct ASTCStrideInfo {
|
||||
u32 z{};
|
||||
u32 index{};
|
||||
};
|
||||
|
||||
const u32 rows = Common::DivideUp(height, block_height);
|
||||
const u32 cols = Common::DivideUp(width, block_width);
|
||||
|
||||
const u32 num_strides = depth * rows;
|
||||
std::vector<ASTCStrideInfo> astc_strides(num_strides);
|
||||
|
||||
for (u32 z = 0; z < depth; ++z) {
|
||||
for (u32 index = 0; index < rows; ++index) {
|
||||
astc_strides.emplace_back(ASTCStrideInfo{
|
||||
.z{z},
|
||||
.index{index},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
auto decompress_stride = [&](const ASTCStrideInfo& stride) {
|
||||
const u32 y = stride.index * block_height;
|
||||
const u32 depth_offset = stride.z * height * width * 4;
|
||||
for (u32 x_index = 0; x_index < cols; ++x_index) {
|
||||
const u32 block_index = (stride.z * rows * cols) + (stride.index * cols) + x_index;
|
||||
const u32 x = x_index * block_width;
|
||||
|
||||
u32 block_index = 0;
|
||||
std::size_t depth_offset = 0;
|
||||
for (u32 z = 0; z < depth; z++) {
|
||||
for (u32 y = 0; y < height; y += block_height) {
|
||||
for (u32 x = 0; x < width; x += block_width) {
|
||||
const std::span<const u8, 16> blockPtr{data.subspan(block_index * 16, 16)};
|
||||
|
||||
// Blocks can be at most 12x12
|
||||
std::array<u32, 12 * 12> uncompData;
|
||||
DecompressBlock(blockPtr, block_width, block_height, uncompData);
|
||||
|
||||
const u32 decompWidth = std::min(block_width, width - x);
|
||||
const u32 decompHeight = std::min(block_height, height - y);
|
||||
u32 decompWidth = std::min(block_width, width - x);
|
||||
u32 decompHeight = std::min(block_height, height - y);
|
||||
|
||||
const std::span<u8> outRow = output.subspan(depth_offset + (y * width + x) * 4);
|
||||
|
||||
for (u32 h = 0; h < decompHeight; ++h) {
|
||||
std::memcpy(outRow.data() + h * width * 4, uncompData.data() + h * block_width,
|
||||
decompWidth * 4);
|
||||
for (u32 jj = 0; jj < decompHeight; jj++) {
|
||||
std::memcpy(outRow.data() + jj * width * 4,
|
||||
uncompData.data() + jj * block_width, decompWidth * 4);
|
||||
}
|
||||
++block_index;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#if __cpp_lib_parallel_algorithm
|
||||
std::for_each(std::execution::par, astc_strides.cbegin(), astc_strides.cend(),
|
||||
decompress_stride);
|
||||
#else
|
||||
std::for_each(astc_strides.cbegin(), astc_strides.cend(), decompress_stride);
|
||||
#endif
|
||||
|
||||
// const u32 rows = Common::DivideUp(height, block_height);
|
||||
// const u32 cols = Common::DivideUp(width, block_width);
|
||||
|
||||
// for (u32 z = 0; z < depth; ++z) {
|
||||
// const u32 depth_offset = z * height * width * 4;
|
||||
// for (u32 y_index = 0; y_index < rows; ++y_index) {
|
||||
// const u32 y = y_index * block_height;
|
||||
// for (u32 x_index = 0; x_index < cols; ++x_index) {
|
||||
// const u32 block_index = (z * rows * cols) + (y_index * cols) + x_index;
|
||||
// const u32 x = x_index * block_width;
|
||||
|
||||
// const std::span<const u8, 16> blockPtr{data.subspan(block_index * 16, 16)};
|
||||
|
||||
// // Blocks can be at most 12x12
|
||||
// std::array<u32, 12 * 12> uncompData;
|
||||
// DecompressBlock(blockPtr, block_width, block_height, uncompData);
|
||||
|
||||
// u32 decompWidth = std::min(block_width, width - x);
|
||||
// u32 decompHeight = std::min(block_height, height - y);
|
||||
|
||||
// const std::span<u8> outRow = output.subspan(depth_offset + (y * width + x) * 4);
|
||||
// for (u32 h = 0; h < decompHeight; ++h) {
|
||||
// std::memcpy(outRow.data() + h * width * 4, uncompData.data() + h *
|
||||
// block_width,
|
||||
// decompWidth * 4);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
depth_offset += height * width * 4;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Tegra::Texture::ASTC
|
||||
|
|
Loading…
Reference in a new issue