Compare commits

..

11 Commits

Author SHA1 Message Date
Laku
e7487bf220 implement invert 2018-08-31 01:55:39 +03:00
Laku
9683918928 Implement POPC 2018-08-30 10:19:46 +03:00
bunnei
4d7e1662c8 Merge pull request #1193 from lioncash/priv
gpu: Make memory_manager private
2018-08-28 12:28:57 -04:00
bunnei
eb4f2d5596 Merge pull request #1192 from lioncash/unused
gl_rasterizer: Remove unused variables
2018-08-28 12:28:13 -04:00
bunnei
d8ba202070 Merge pull request #1191 from lioncash/noexcept
hle/result: Make ResultVal's move constructor as noexcept
2018-08-28 12:27:48 -04:00
bunnei
72e4499a9e Merge pull request #1194 from lioncash/alloc
gl_shader_cache: Remove unused program_code vector in GetShaderAddress()
2018-08-28 11:27:44 -04:00
Lioncash
45fb74d262 gpu: Make memory_manager private
Makes the class interface consistent and provides accessors for
obtaining a reference to the memory manager instance.

Given we also return references, this makes our more flimsy uses of
const apparent, given const doesn't propagate through pointers in the
way one would typically expect. This makes our mutable state more
apparent in some places.
2018-08-28 11:11:50 -04:00
Lioncash
6771a18c6c gl_rasterizer: Remove unused variables 2018-08-28 10:46:29 -04:00
bunnei
0d2435343a Merge pull request #1190 from FearlessTobi/im-so-retarded
yuzu: Fix two stupid errors made in #1141
2018-08-28 09:57:05 -04:00
Lioncash
f1bc62bb4c hle/result: Make ResultVal's move constructor as noexcept
Many containers within the standard library provide different behaviors
based on whether or not a move constructor/assignment operator can be
guaranteed not to throw or not.

Notably, implementations will generally use std::move_if_noexcept (or an
internal implementation of it) to provide strong exception guarantees.
If a move constructor potentially throws (in other words, is not
noexcept), then certain behaviors will create copies, rather than moving
the values.

For example, consider std::vector. When a std::vector calls resize(),
there are two ways the elements can be relocated to the new block of
memory (if a reallocation happens), by copy, or by moving the existing
elements into the new block of memory. If a type does not have a
guarantee that it will not throw in the move constructor, a copy will
happen. However, if it can be guaranteed that the move constructor won't
throw, then the elements will be moved.

This just allows ResultVal to be moved instead of copied all the time if
ever used in conjunction with containers for whatever reason.
2018-08-28 09:39:50 -04:00
fearlessTobi
4a56931703 Fix two stupid errors made in #1141 2018-08-28 15:16:03 +02:00
12 changed files with 63 additions and 31 deletions

View File

@@ -227,7 +227,7 @@ public:
}
}
ResultVal(ResultVal&& o) : result_code(o.result_code) {
ResultVal(ResultVal&& o) noexcept : result_code(o.result_code) {
if (!o.empty()) {
new (&object) T(std::move(o.object));
}

View File

@@ -56,9 +56,9 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>&
auto& gpu = Core::System::GetInstance().GPU();
const u64 size{static_cast<u64>(params.pages) * static_cast<u64>(params.page_size)};
if (params.flags & 1) {
params.offset = gpu.memory_manager->AllocateSpace(params.offset, size, 1);
params.offset = gpu.MemoryManager().AllocateSpace(params.offset, size, 1);
} else {
params.offset = gpu.memory_manager->AllocateSpace(size, params.align);
params.offset = gpu.MemoryManager().AllocateSpace(size, params.align);
}
std::memcpy(output.data(), &params, output.size());
@@ -88,7 +88,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)
u64 size = static_cast<u64>(entry.pages) << 0x10;
ASSERT(size <= object->size);
Tegra::GPUVAddr returned = gpu.memory_manager->MapBufferEx(object->addr, offset, size);
Tegra::GPUVAddr returned = gpu.MemoryManager().MapBufferEx(object->addr, offset, size);
ASSERT(returned == offset);
}
std::memcpy(output.data(), entries.data(), output.size());
@@ -125,9 +125,9 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
auto& gpu = Core::System::GetInstance().GPU();
if (params.flags & 1) {
params.offset = gpu.memory_manager->MapBufferEx(object->addr, params.offset, object->size);
params.offset = gpu.MemoryManager().MapBufferEx(object->addr, params.offset, object->size);
} else {
params.offset = gpu.memory_manager->MapBufferEx(object->addr, object->size);
params.offset = gpu.MemoryManager().MapBufferEx(object->addr, object->size);
}
// Create a new mapping entry for this operation.
@@ -161,7 +161,7 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou
itr->second.size);
auto& gpu = system_instance.GPU();
params.offset = gpu.memory_manager->UnmapBuffer(params.offset, itr->second.size);
params.offset = gpu.MemoryManager().UnmapBuffer(params.offset, itr->second.size);
buffer_mappings.erase(itr->second.offset);

View File

@@ -264,7 +264,7 @@ void RasterizerMarkRegionCached(Tegra::GPUVAddr gpu_addr, u64 size, bool cached)
u64 num_pages = ((gpu_addr + size - 1) >> PAGE_BITS) - (gpu_addr >> PAGE_BITS) + 1;
for (unsigned i = 0; i < num_pages; ++i, gpu_addr += PAGE_SIZE) {
boost::optional<VAddr> maybe_vaddr =
Core::System::GetInstance().GPU().memory_manager->GpuToCpuAddress(gpu_addr);
Core::System::GetInstance().GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
// The GPU <-> CPU virtual memory mapping is not 1:1
if (!maybe_vaddr) {
LOG_ERROR(HW_Memory,
@@ -346,7 +346,7 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
const VAddr overlap_end = std::min(end, region_end);
const std::vector<Tegra::GPUVAddr> gpu_addresses =
system_instance.GPU().memory_manager->CpuToGpuAddress(overlap_start);
system_instance.GPU().MemoryManager().CpuToGpuAddress(overlap_start);
if (gpu_addresses.empty()) {
return;

View File

@@ -326,6 +326,10 @@ union Instruction {
BitField<49, 1, u64> negate_a;
} alu_integer;
union {
BitField<40, 1, u64> invert;
} popc;
union {
BitField<39, 3, u64> pred;
BitField<42, 1, u64> neg_pred;
@@ -643,6 +647,9 @@ public:
ISCADD_C, // Scale and Add
ISCADD_R,
ISCADD_IMM,
POPC_C,
POPC_R,
POPC_IMM,
SEL_C,
SEL_R,
SEL_IMM,
@@ -864,6 +871,9 @@ private:
INST("0100110000011---", Id::ISCADD_C, Type::ArithmeticInteger, "ISCADD_C"),
INST("0101110000011---", Id::ISCADD_R, Type::ArithmeticInteger, "ISCADD_R"),
INST("0011100-00011---", Id::ISCADD_IMM, Type::ArithmeticInteger, "ISCADD_IMM"),
INST("0100110000001---", Id::POPC_C, Type::ArithmeticInteger, "POPC_C"),
INST("0101110000001---", Id::POPC_R, Type::ArithmeticInteger, "POPC_R"),
INST("0011100-00001---", Id::POPC_IMM, Type::ArithmeticInteger, "POPC_IMM"),
INST("0100110010100---", Id::SEL_C, Type::ArithmeticInteger, "SEL_C"),
INST("0101110010100---", Id::SEL_R, Type::ArithmeticInteger, "SEL_R"),
INST("0011100-10100---", Id::SEL_IMM, Type::ArithmeticInteger, "SEL_IMM"),

View File

@@ -22,7 +22,7 @@ u32 FramebufferConfig::BytesPerPixel(PixelFormat format) {
}
GPU::GPU(VideoCore::RasterizerInterface& rasterizer) {
memory_manager = std::make_unique<MemoryManager>();
memory_manager = std::make_unique<Tegra::MemoryManager>();
maxwell_3d = std::make_unique<Engines::Maxwell3D>(rasterizer, *memory_manager);
fermi_2d = std::make_unique<Engines::Fermi2D>(*memory_manager);
maxwell_compute = std::make_unique<Engines::MaxwellCompute>();
@@ -31,12 +31,20 @@ GPU::GPU(VideoCore::RasterizerInterface& rasterizer) {
GPU::~GPU() = default;
Engines::Maxwell3D& GPU::Maxwell3D() {
return *maxwell_3d;
}
const Engines::Maxwell3D& GPU::Maxwell3D() const {
return *maxwell_3d;
}
Engines::Maxwell3D& GPU::Maxwell3D() {
return *maxwell_3d;
MemoryManager& GPU::MemoryManager() {
return *memory_manager;
}
const MemoryManager& GPU::MemoryManager() const {
return *memory_manager;
}
u32 RenderTargetBytesPerPixel(RenderTargetFormat format) {

View File

@@ -117,18 +117,24 @@ public:
/// Processes a command list stored at the specified address in GPU memory.
void ProcessCommandList(GPUVAddr address, u32 size);
/// Returns a const reference to the Maxwell3D GPU engine.
const Engines::Maxwell3D& Maxwell3D() const;
/// Returns a reference to the Maxwell3D GPU engine.
Engines::Maxwell3D& Maxwell3D();
std::unique_ptr<MemoryManager> memory_manager;
/// Returns a const reference to the Maxwell3D GPU engine.
const Engines::Maxwell3D& Maxwell3D() const;
/// Returns a reference to the GPU memory manager.
Tegra::MemoryManager& MemoryManager();
/// Returns a const reference to the GPU memory manager.
const Tegra::MemoryManager& MemoryManager() const;
private:
/// Writes a single register in the engine bound to the specified subchannel
void WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params);
std::unique_ptr<Tegra::MemoryManager> memory_manager;
/// Mapping of command subchannels to their bound engine ids.
std::unordered_map<u32, EngineID> bound_engines;

View File

@@ -211,7 +211,6 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr
buffer_ptr += sizeof(ubo);
buffer_offset += sizeof(ubo);
const Tegra::GPUVAddr addr{gpu.regs.code_address.CodeAddress() + shader_config.offset};
Shader shader{shader_cache.GetStageProgram(program)};
switch (program) {
@@ -425,8 +424,8 @@ std::tuple<u8*, GLintptr, GLintptr> RasterizerOpenGL::UploadMemory(u8* buffer_pt
std::tie(buffer_ptr, buffer_offset) = AlignBuffer(buffer_ptr, buffer_offset, alignment);
GLintptr uploaded_offset = buffer_offset;
const auto& memory_manager = Core::System::GetInstance().GPU().memory_manager;
const boost::optional<VAddr> cpu_addr{memory_manager->GpuToCpuAddress(gpu_addr)};
auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager();
const boost::optional<VAddr> cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)};
Memory::ReadBlock(*cpu_addr, buffer_ptr, size);
buffer_ptr += size;
@@ -459,7 +458,6 @@ void RasterizerOpenGL::DrawArrays() {
// Draw the vertex batch
const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()};
const unsigned vertex_num{is_indexed ? regs.index_array.count : regs.vertex_buffer.count};
state.draw.vertex_buffer = stream_buffer.GetHandle();
state.Apply();

View File

@@ -168,8 +168,8 @@ static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType
}
VAddr SurfaceParams::GetCpuAddr() const {
const auto& gpu = Core::System::GetInstance().GPU();
return *gpu.memory_manager->GpuToCpuAddress(addr);
auto& gpu = Core::System::GetInstance().GPU();
return *gpu.MemoryManager().GpuToCpuAddress(addr);
}
static bool IsPixelFormatASTC(PixelFormat format) {
@@ -220,14 +220,14 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_bu
Tegra::GPUVAddr addr) {
constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT;
constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
const auto& gpu = Core::System::GetInstance().GPU();
auto& gpu = Core::System::GetInstance().GPU();
if (morton_to_gl) {
// With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
// pixel values.
const u32 tile_size{IsFormatBCn(format) ? 4U : 1U};
const std::vector<u8> data =
Tegra::Texture::UnswizzleTexture(*gpu.memory_manager->GpuToCpuAddress(addr), tile_size,
Tegra::Texture::UnswizzleTexture(*gpu.MemoryManager().GpuToCpuAddress(addr), tile_size,
bytes_per_pixel, stride, height, block_height);
const size_t size_to_copy{std::min(gl_buffer.size(), data.size())};
gl_buffer.assign(data.begin(), data.begin() + size_to_copy);
@@ -237,7 +237,7 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_bu
LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
VideoCore::MortonCopyPixels128(
stride, height, bytes_per_pixel, gl_bytes_per_pixel,
Memory::GetPointer(*gpu.memory_manager->GpuToCpuAddress(addr)), gl_buffer.data(),
Memory::GetPointer(*gpu.MemoryManager().GpuToCpuAddress(addr)), gl_buffer.data(),
morton_to_gl);
}
}
@@ -754,9 +754,9 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres
return {};
}
const auto& gpu = Core::System::GetInstance().GPU();
auto& gpu = Core::System::GetInstance().GPU();
// Don't try to create any entries in the cache if the address of the texture is invalid.
if (gpu.memory_manager->GpuToCpuAddress(params.addr) == boost::none)
if (gpu.MemoryManager().GpuToCpuAddress(params.addr) == boost::none)
return {};
// Look up surface in the cache based on address
@@ -848,7 +848,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
"reinterpretation but the texture is tiled.");
}
size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes();
auto address = Core::System::GetInstance().GPU().memory_manager->GpuToCpuAddress(
auto address = Core::System::GetInstance().GPU().MemoryManager().GpuToCpuAddress(
new_params.addr + params.SizeInBytes());
std::vector<u8> data(remaining_size);
Memory::ReadBlock(*address, data.data(), data.size());

View File

@@ -1302,6 +1302,15 @@ private:
"((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1);
break;
}
case OpCode::Id::POPC_C:
case OpCode::Id::POPC_R:
case OpCode::Id::POPC_IMM: {
if (instr.popc.invert) {
op_b = "~(" + op_b + ')';
}
regs.SetRegisterToInteger(instr.gpr0, true, 0, "bitCount(" + op_b + ')', 1, 1);
break;
}
case OpCode::Id::SEL_C:
case OpCode::Id::SEL_R:
case OpCode::Id::SEL_IMM: {

View File

@@ -382,7 +382,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
// TODO: Implement a good way to visualize alpha components!
QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32);
boost::optional<VAddr> address = gpu.memory_manager->GpuToCpuAddress(surface_address);
boost::optional<VAddr> address = gpu.MemoryManager().GpuToCpuAddress(surface_address);
// TODO(bunnei): Will not work with BCn formats that swizzle 4x4 tiles.
// Needs to be fixed if we plan to use this feature more, otherwise we may remove it.
@@ -443,7 +443,7 @@ void GraphicsSurfaceWidget::SaveSurface() {
pixmap->save(&file, "PNG");
} else if (selectedFilter == bin_filter) {
auto& gpu = Core::System::GetInstance().GPU();
boost::optional<VAddr> address = gpu.memory_manager->GpuToCpuAddress(surface_address);
boost::optional<VAddr> address = gpu.MemoryManager().GpuToCpuAddress(surface_address);
const u8* buffer = Memory::GetPointer(*address);
ASSERT_MSG(buffer != nullptr, "Memory not accessible");

View File

@@ -893,6 +893,7 @@ void GMainWindow::OnStartGame() {
ui.action_Pause->setEnabled(true);
ui.action_Stop->setEnabled(true);
ui.action_Restart->setEnabled(true);
}
void GMainWindow::OnPauseGame() {
@@ -901,7 +902,6 @@ void GMainWindow::OnPauseGame() {
ui.action_Start->setEnabled(true);
ui.action_Pause->setEnabled(false);
ui.action_Stop->setEnabled(true);
ui.action_Restart->setEnabled(true);
}
void GMainWindow::OnStopGame() {

View File

@@ -74,6 +74,7 @@
<addaction name="action_Start"/>
<addaction name="action_Pause"/>
<addaction name="action_Stop"/>
<addaction name="action_Restart"/>
<addaction name="separator"/>
<addaction name="action_Configure"/>
</widget>