Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ GuestTextureResource DecodeTextureResource(std::span<const std::uint32_t> words)
Require(width == height, "guest cube texture descriptor is not square");
Require(baseArray <= depth, "guest cube texture descriptor has a base array past its last array slice");
if (baseArray == depth) depth += 5u;
if ((depth - baseArray + 1u) % 6u != 0) {
Require(false, "guest cube texture descriptor does not contain a multiple of 6 array slices" +
if (depth - baseArray + 1u < 6u) {
Require(false, "guest cube texture descriptor holds fewer than 6 array slices" +
describe() + " (base array " + std::to_string(baseArray) + ")");
}
break;
Expand Down
8 changes: 4 additions & 4 deletions core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ Texture::Texture(const Context& context, TextureDetiler& detiler, const GuestTex
const auto viewLevelCount = std::min(descriptor.lastLevel, descriptor.mipCount - 1u) - descriptor.baseLevel + 1u;
const auto viewLayerCount = geometry.imageLayers - descriptor.baseArray;
if (descriptor.dimension == TextureDimension::kCube) {
Require(viewLayerCount % 6u == 0, "guest cube texture view does not contain a multiple of 6 array slices");
Require(viewLayerCount >= 6u, "guest cube texture view holds fewer than 6 array slices");
}

VkImageViewCreateInfo viewInfo{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
Expand Down Expand Up @@ -552,7 +552,7 @@ Texture::Texture(const Context& context, const std::shared_ptr<StorageTexture>&
const auto viewLevelCount = std::min(descriptor.lastLevel, descriptor.mipCount - 1u) - descriptor.baseLevel + 1u;
const auto viewLayerCount = geometry.imageLayers - descriptor.baseArray;
if (descriptor.dimension == TextureDimension::kCube) {
Require(viewLayerCount % 6u == 0, "guest cube texture view does not contain a multiple of 6 array slices");
Require(viewLayerCount >= 6u, "guest cube texture view holds fewer than 6 array slices");
}
VkImageViewCreateInfo viewInfo{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
viewInfo.image = image;
Expand Down Expand Up @@ -667,7 +667,7 @@ Texture::Texture(const Context& context, const std::shared_ptr<StorageTexture>&
const auto viewLevelCount = std::min(descriptor.lastLevel, descriptor.mipCount - 1u) - descriptor.baseLevel + 1u;
const auto viewLayerCount = geometry.imageLayers - descriptor.baseArray;
if (descriptor.dimension == TextureDimension::kCube) {
Require(viewLayerCount % 6u == 0, "guest cube texture view does not contain a multiple of 6 array slices");
Require(viewLayerCount >= 6u, "guest cube texture view holds fewer than 6 array slices");
}
VkImageViewCreateInfo viewInfo{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
viewInfo.image = image;
Expand Down Expand Up @@ -846,7 +846,7 @@ Texture::Texture(const Context& context, const std::shared_ptr<StorageTexture>&
const auto viewLevelCount = std::min(descriptor.lastLevel, descriptor.mipCount - 1u) - descriptor.baseLevel + 1u;
const auto viewLayerCount = std::min(geometry.imageLayers, source->ImageLayers()) - descriptor.baseArray;
if (descriptor.dimension == TextureDimension::kCube) {
Require(viewLayerCount % 6u == 0, "guest cube texture view does not contain a multiple of 6 array slices");
Require(viewLayerCount >= 6u, "guest cube texture view holds fewer than 6 array slices");
}
VkImageViewCreateInfo viewInfo{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
viewInfo.image = source->Image();
Expand Down
11 changes: 8 additions & 3 deletions core/libs/prx/libSceAgcDriver/tests/GuestTextureResource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,14 @@ void RunGuestTextureResourceTests() {
Fields cubeBadArray = cube;
cubeBadArray.baseArray = 6;
rejectFields(cubeBadArray, "base array past its last array slice");
Fields cubeNotMultiple = cube;
cubeNotMultiple.depth = 4;
rejectFields(cubeNotMultiple, "multiple of 6");
Fields cubeExtraSlice = cube;
cubeExtraSlice.depth = 6;
result = DecodeTextureResource(pack(cubeExtraSlice));
Require(result.baseArray == 0 && result.depthOrLastArray == 6, "a cube descriptor with a slice past its last whole cube lost a slice");
Require(DescribeSurface(result).imageLayers == 7, "a cube allocation with a slice past its last whole cube omitted it");
Fields cubePartial = cube;
cubePartial.depth = 4;
rejectFields(cubePartial, "fewer than 6 array slices");

Fields multisampled = base;
multisampled.typeRaw = 14;
Expand Down
66 changes: 66 additions & 0 deletions core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7572,6 +7572,70 @@ void singleCubeTests(const Device& device, Recorder& recorder) {
}
}

void cubeExtraSliceTests(const Device& device, Recorder& recorder) {
auto context = device.GetContext();
TextureDetiler detiler(context);
context.detiler = &detiler;
SampleProgram program(context, recorder, SAMPLE_ARRAY_SPV);
const VkComponentMapping identity{};
std::array<std::uint32_t, 8> words{0x1000u, (56u << 20u) | (3u << 30u), 15u | (63u << 14u), 0xb0000facu, 6u, 0, 0, 0};
auto resource = DecodeTextureResource(words);
const auto geometry = DescribeSurface(resource);
Require(geometry.imageLayers == 7u, "a cube with a slice past its last whole cube does not allocate it");
std::vector<std::byte> memory(static_cast<std::size_t>(geometry.guestBytes) + 256);
auto* surface = reinterpret_cast<std::byte*>((reinterpret_cast<std::uintptr_t>(memory.data()) + 255) & ~std::uintptr_t{255});
for (std::uint32_t layer = 0; layer < geometry.imageLayers; ++layer) {
std::memset(surface + geometry.GuestLayerOffset(layer), 16 * (layer + 1), static_cast<std::size_t>(geometry.layerBytes));
}
resource.baseAddress = reinterpret_cast<std::uint64_t>(surface);
const std::span<const std::byte> snapshot(surface, static_cast<std::size_t>(geometry.guestBytes));
Texture texture(context, detiler, resource, identity, snapshot);
auto storage = StorageTexture::Create(context, detiler, resource, 0);
recorder.Keep(storage);
Texture storageView(context, storage, resource, identity);
const auto wordCube = [&words](std::vector<std::byte>& backing, std::uint32_t format, const std::function<std::uint32_t(std::uint32_t)>& word) {
auto cubeWords = words;
cubeWords[1] = (format << 20u) | (3u << 30u);
auto described = DecodeTextureResource(cubeWords);
const auto layout = DescribeSurface(described);
backing.assign(static_cast<std::size_t>(layout.guestBytes) + 256, std::byte{});
auto* base = reinterpret_cast<std::byte*>((reinterpret_cast<std::uintptr_t>(backing.data()) + 255) & ~std::uintptr_t{255});
for (std::uint32_t layer = 0; layer < layout.imageLayers; ++layer) {
const auto value = word(layer);
for (std::uint64_t offset = 0; offset < layout.layerBytes; offset += sizeof(value)) std::memcpy(base + layout.GuestLayerOffset(layer) + offset, &value, sizeof(value));
}
described.baseAddress = reinterpret_cast<std::uint64_t>(base);
return described;
};
std::vector<std::byte> depthMemory;
const auto depth = wordCube(depthMemory, 22u, [](std::uint32_t layer) {
const float value = static_cast<float>(layer + 1) / 8.0f;
std::uint32_t bits = 0;
std::memcpy(&bits, &value, sizeof(bits));
return bits;
});
auto depthStorage = StorageTexture::Create(context, detiler, depth, 0);
recorder.Keep(depthStorage);
Require(Texture::CanDepthCopyFrom(*depthStorage, depth), "a cube with a slice past its last whole cube cannot take a depth copy");
Texture depthCopy(context, depthStorage, depth, identity, Texture::DepthCopyTag{});
depthCopy.RefreshDepthCopy();
constexpr std::array<std::uint32_t, 7> unsignedFloats{960u, 1024u, 1056u, 1088u, 1104u, 1120u, 1136u};
std::vector<std::byte> repackMemory;
const auto repacked = wordCube(repackMemory, 43u, [&unsignedFloats](std::uint32_t layer) { return unsignedFloats[layer] << 21u; });
auto repackStorage = StorageTexture::Create(context, detiler, repacked, 0);
recorder.Keep(repackStorage);
Require(Texture::CanRepackCopyFrom(*repackStorage, repacked), "a cube with a slice past its last whole cube cannot take a repacked copy");
Texture repackCopy(context, repackStorage, repacked, identity, Texture::RepackCopyTag{});
repackCopy.RefreshDepthCopy();
for (std::uint32_t layer = 0; layer < geometry.imageLayers; ++layer) {
const auto expected = 16.0f * (layer + 1) / 255.0f;
expectRed(program.Red(texture.View(), texture.Layout(), 0, static_cast<float>(layer)), expected, "a cube snapshot with a slice past its last whole cube sampled the wrong slice");
expectRed(program.Red(storageView.View(), storageView.Layout(), 0, static_cast<float>(layer)), expected, "a cube storage view with a slice past its last whole cube sampled the wrong slice");
expectRed(program.Red(depthCopy.View(), depthCopy.Layout(), 0, static_cast<float>(layer)), static_cast<float>(layer + 1) / 8.0f, "a cube depth copy with a slice past its last whole cube sampled the wrong slice");
expectRed(program.Red(repackCopy.View(), repackCopy.Layout(), 0, static_cast<float>(layer)), static_cast<float>(layer + 1), "a cube repacked copy with a slice past its last whole cube sampled the wrong slice");
}
}

struct SampledViewProbe {
Context& context;
PFN_vkGetDeviceProcAddr resolver;
Expand Down Expand Up @@ -8880,6 +8944,7 @@ int main(int argc, char** argv) {
}
if (argc == 2 && std::string_view(argv[1]) == "--cube-only") {
singleCubeTests(device, recorder);
cubeExtraSliceTests(device, recorder);
std::cout << "Single cube snapshot and storage sampling tests passed\n";
return 0;
}
Expand Down Expand Up @@ -9108,6 +9173,7 @@ int main(int argc, char** argv) {
firstLayerViewTests(device, recorder);
sampledStorageBaseLevelUsageTests(device, recorder);
singleCubeTests(device, recorder);
cubeExtraSliceTests(device, recorder);
atomicViewTests(device, recorder);
metadataPassTests(device, recorder);
cmaskPassTests(device, recorder);
Expand Down
Loading
Loading