blob: 3c7cf84fe0da414597f4910c13b982d39a759690 [file]
/* Copyright (c) 2026 Valve Corporation
* Copyright (c) 2026 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "gpu_dump.h"
#include <cstdint>
#include "chassis/layer_object_id.h"
#include "generated/dispatch_functions.h"
#include "state_tracker/buffer_state.h"
#include "state_tracker/device_memory_state.h"
namespace gpudump {
GpuDump::GpuDump(vvl::DispatchDevice* dev, gpudump::Instance* instance_vo)
: vvl::DeviceProxy(dev, instance_vo, LayerObjectTypeGpuDump) {}
GpuDump::~GpuDump() {}
std::vector<uint8_t> GpuDump::CopyDataFromMemory(VkDeviceAddress memory_addresss, VkDeviceSize copy_size) {
std::vector<uint8_t> result;
vvl::span<vvl::Buffer* const> buffer_list = device_state->GetBuffersByAddress(memory_addresss);
if (buffer_list.empty()) {
return result;
}
auto buffer_state = *buffer_list.begin();
const vvl::DeviceMemory& memory_state = *buffer_state->MemoryState();
// Prevent copying OOB of a buffer
if ((memory_addresss + copy_size) > buffer_state->DeviceAddressRange().end) {
return result;
}
VkDeviceSize offset = memory_addresss - buffer_state->DeviceAddressRange().begin;
if (memory_state.mappable) {
uint8_t* data_ptr = static_cast<uint8_t*>(memory_state.p_driver_data);
if (!memory_state.p_driver_data) {
// Just use WHOLE_SIZE to avoid issues with partial mappings
// Example:
// The |memory_address| is 0x1001 and |copy_size| is 4, the driver (or at least TestICD) will return back something
// aligned to a value like 64, so if the buffer is only 64 bytes, you will now be accessing data over it
DispatchMapMemory(device, memory_state.VkHandle(), offset, VK_WHOLE_SIZE, 0, (void**)&data_ptr);
// Skip checking if coherent memory or not
VkMappedMemoryRange memory_range = vku::InitStructHelper();
memory_range.memory = memory_state.VkHandle();
memory_range.offset = offset;
memory_range.size = copy_size;
DispatchInvalidateMappedMemoryRanges(device, 1, &memory_range);
}
data_ptr += offset;
result.resize(static_cast<uint32_t>(copy_size));
memcpy(result.data(), data_ptr, static_cast<uint32_t>(copy_size));
if (!memory_state.p_driver_data) {
DispatchUnmapMemory(device, memory_state.VkHandle());
}
} else {
// TODO - Handle non-host visible memory
// When we add, we need to guard against if trying to read non-aligned data
// (which should have a warning already)
}
return result;
}
// return for warning if no buffer found
bool GpuDump::ListBuffers(std::ostringstream& ss, VkDeviceAddress address, uint32_t indents, bool new_line_start) {
if (new_line_start) {
ss << "\n";
}
auto buffer_states = GetBuffersByAddress(address);
for (uint32_t i = 0; i < indents; i++) {
ss << " ";
}
for (uint32_t i = 0; i < buffer_states.size(); i++) {
if (i != 0) {
ss << '\n';
for (uint32_t j = 0; j < indents; j++) {
ss << " ";
}
}
auto& buffer_state = buffer_states[i];
ss << "- " << buffer_state->Describe(*this);
}
if (buffer_states.empty()) {
ss << "- [WARNING] No VkBuffer found at 0x" << std::hex << address;
}
if (!new_line_start) {
ss << "\n";
}
return buffer_states.empty();
}
} // namespace gpudump