Merge branch 'master' into TemporaryHackishBranch

# Conflicts:
#	GPU/GLES/FramebufferManagerGLES.cpp
~Due to restoration of the BGRA path
This commit is contained in:
LunaMoo committed 2017-11-01 22:55:58 +01:00
commit 5f3d6c57dd
137 files changed
+4731 -4088

No files matched your search

+1 -1
View File
@@ -23,7 +23,7 @@ indent_style = space
indent_size = 4
[Core/Dialog/PSPOskDialog.cpp]
charset = utf-16le
charset = utf-8-bom
[ext/native/tools/kanjifilter.h]
# This file may need to force a BOM so compilers treat as utf-8.
+1
View File
@@ -37,6 +37,7 @@ PPSSPPDebug64.exe.manifest
PPSSPPDebug.exe.manifest
assets/flash0
UWP/icph
UWP/.vs
# For Mac
.DS_Store
+15 -3
View File
@@ -742,7 +742,10 @@ elseif(TARGET SDL2::SDL2)
set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm)
set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY})
elseif(USING_EGL)
set(nativeExtraLibs ${nativeExtraLibs} pthread EGL)
if(NOT EGL_LIBRARIES)
set(EGL_LIBRARIES EGL)
endif()
set(nativeExtraLibs ${nativeExtraLibs} pthread ${EGL_LIBRARIES})
endif()
set(TargetBin PPSSPPSDL)
elseif(WIN32)
@@ -800,7 +803,13 @@ endif()
set(THIN3D_PLATFORMS ext/native/thin3d/thin3d_gl.cpp)
if(VULKAN)
set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS} ext/native/thin3d/thin3d_vulkan.cpp)
set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS}
ext/native/thin3d/thin3d_vulkan.cpp
ext/native/thin3d/VulkanRenderManager.cpp
ext/native/thin3d/VulkanRenderManager.h
ext/native/thin3d/VulkanQueueRunner.cpp
ext/native/thin3d/VulkanQueueRunner.h
ext/native/thin3d/DataFormat.h)
endif()
if(WIN32)
set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS}
@@ -1165,6 +1174,7 @@ set(GPU_VULKAN
GPU/Vulkan/ShaderManagerVulkan.h
GPU/Vulkan/StateMappingVulkan.cpp
GPU/Vulkan/StateMappingVulkan.h
GPU/Vulkan/StencilBufferVulkan.cpp
GPU/Vulkan/TextureCacheVulkan.cpp
GPU/Vulkan/TextureCacheVulkan.h
GPU/Vulkan/TextureScalerVulkan.cpp
@@ -1257,6 +1267,8 @@ set(GPU_SOURCES
GPU/Common/ShaderCommon.h
GPU/Common/SplineCommon.cpp
GPU/Common/SplineCommon.h
GPU/Common/StencilCommon.cpp
GPU/Common/StencilCommon.h
GPU/Common/SoftwareTransformCommon.cpp
GPU/Common/SoftwareTransformCommon.h
GPU/Common/VertexDecoderCommon.cpp
@@ -1614,7 +1626,7 @@ add_library(${CoreLibName} ${CoreLinkType}
if(ANDROID)
set(CoreExtraLibs ${CoreExtraLibs} android)
if(X86_64)
set(CoreExtraLibs -Wl,--gc-sections -Wl,--exclude-libs,ALL)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-Bsymbolic")
endif()
endif()
+2 -1
View File
@@ -136,6 +136,7 @@ void ConsoleListener::Open()
// Set the console window title
SetConsoleTitle(title_.c_str());
SetConsoleCP(CP_UTF8);
SetConsoleOutputCP(CP_UTF8);
// Set letter space
LetterSpace(openWidth_, LOG_MAX_DISPLAY_LINES);
@@ -503,7 +504,7 @@ void ConsoleListener::WriteToConsole(LogTypes::LOG_LEVELS Level, const char *Tex
SetConsoleTextAttribute(hConsole, Color);
int wlen = MultiByteToWideChar(CP_UTF8, 0, Text, (int)Len, NULL, NULL);
MultiByteToWideChar(CP_UTF8, 0, Text, (int)Len, tempBuf, wlen);
WriteConsole(hConsole, tempBuf, (DWORD)Len, &cCharsWritten, NULL);
WriteConsole(hConsole, tempBuf, (DWORD)wlen, &cCharsWritten, NULL);
}
#endif
+40 -40
View File
@@ -20,7 +20,7 @@ inline bool KeyEquals(const K &a, const K &b) {
return !memcmp(&a, &b, sizeof(K));
}
enum class BucketState {
enum class BucketState : uint8_t {
FREE,
TAKEN,
REMOVED, // for linear probing to work (and removal during deletion) we need tombstones
@@ -35,6 +35,7 @@ class DenseHashMap {
public:
DenseHashMap(int initialCapacity) : capacity_(initialCapacity) {
map.resize(initialCapacity);
state.resize(initialCapacity);
}
// Returns nullptr if no entry was found.
@@ -44,9 +45,9 @@ public:
// No? Let's go into search mode. Linear probing.
uint32_t p = pos;
while (true) {
if (map[p].state == BucketState::TAKEN && KeyEquals(key, map[p].key))
if (state[p] == BucketState::TAKEN && KeyEquals(key, map[p].key))
return map[p].value;
else if (map[p].state == BucketState::FREE)
else if (state[p] == BucketState::FREE)
return NullValue;
p = (p + 1) & mask; // If the state is REMOVED, we just keep on walking.
if (p == pos)
@@ -65,7 +66,7 @@ public:
uint32_t pos = HashKey(key) & mask;
uint32_t p = pos;
while (true) {
if (map[p].state == BucketState::TAKEN) {
if (state[p] == BucketState::TAKEN) {
if (KeyEquals(key, map[p].key)) {
Crash(); // Bad! We already got this one. Let's avoid this case.
return false;
@@ -81,10 +82,10 @@ public:
Crash();
}
}
if (map[p].state == BucketState::REMOVED) {
if (state[p] == BucketState::REMOVED) {
removedCount_--;
}
map[p].state = BucketState::TAKEN;
state[p] = BucketState::TAKEN;
map[p].key = key;
map[p].value = value;
count_++;
@@ -95,10 +96,10 @@ public:
uint32_t mask = capacity_ - 1;
uint32_t pos = HashKey(key) & mask;
uint32_t p = pos;
while (map[p].state != BucketState::FREE) {
if (map[p].state == BucketState::TAKEN && KeyEquals(key, map[p].key)) {
while (state[p] != BucketState::FREE) {
if (state[p] == BucketState::TAKEN && KeyEquals(key, map[p].key)) {
// Got it! Mark it as removed.
map[p].state = BucketState::REMOVED;
state[p] = BucketState::REMOVED;
removedCount_++;
count_--;
return true;
@@ -118,17 +119,15 @@ public:
template<class T>
inline void Iterate(T func) {
for (auto &iter : map) {
if (iter.state == BucketState::TAKEN) {
func(iter.key, iter.value);
for (size_t i = 0; i < map.size(); i++) {
if (state[i] == BucketState::TAKEN) {
func(map[i].key, map[i].value);
}
}
}
void Clear() {
// TODO: Speedup?
map.clear();
map.resize(capacity_);
memset(state.data(), (int)BucketState::FREE, state.size());
}
void Rebuild() {
@@ -147,23 +146,24 @@ private:
// We simply move out the existing data, then we re-insert the old.
// This is extremely non-atomic and will need synchronization.
std::vector<Pair> old = std::move(map);
std::vector<BucketState> oldState = std::move(state);
capacity_ *= factor;
map.clear();
map.resize(capacity_);
state.resize(capacity_);
count_ = 0; // Insert will update it.
removedCount_ = 0;
for (auto &iter : old) {
if (iter.state == BucketState::TAKEN) {
Insert(iter.key, iter.value);
for (size_t i = 0; i < old.size(); i++) {
if (oldState[i] == BucketState::TAKEN) {
Insert(old[i].key, old[i].value);
}
}
}
struct Pair {
BucketState state;
Key key;
Value value;
};
std::vector<Pair> map;
std::vector<BucketState> state;
int capacity_;
int count_ = 0;
int removedCount_ = 0;
@@ -176,6 +176,7 @@ class PrehashMap {
public:
PrehashMap(int initialCapacity) : capacity_(initialCapacity) {
map.resize(initialCapacity);
state.resize(initialCapacity);
}
// Returns nullptr if no entry was found.
@@ -185,9 +186,9 @@ public:
// No? Let's go into search mode. Linear probing.
uint32_t p = pos;
while (true) {
if (map[p].state == BucketState::TAKEN && hash == map[p].hash)
if (state[p] == BucketState::TAKEN && hash == map[p].hash)
return map[p].value;
else if (map[p].state == BucketState::FREE)
else if (state[p] == BucketState::FREE)
return NullValue;
p = (p + 1) & mask; // If the state is REMOVED, we just keep on walking.
if (p == pos)
@@ -205,8 +206,8 @@ public:
uint32_t mask = capacity_ - 1;
uint32_t pos = hash & mask;
uint32_t p = pos;
while (map[p].state != BucketState::FREE) {
if (map[p].state == BucketState::TAKEN) {
while (state[p] != BucketState::FREE) {
if (state[p] == BucketState::TAKEN) {
if (hash == map[p].hash)
return false; // Bad!
} else {
@@ -219,10 +220,10 @@ public:
Crash();
}
}
if (map[p].state == BucketState::REMOVED) {
if (state[p] == BucketState::REMOVED) {
removedCount_--;
}
map[p].state = BucketState::TAKEN;
state[p] = BucketState::TAKEN;
map[p].hash = hash;
map[p].value = value;
count_++;
@@ -233,10 +234,10 @@ public:
uint32_t mask = capacity_ - 1;
uint32_t pos = hash & mask;
uint32_t p = pos;
while (map[p].state != BucketState::FREE) {
if (map[p].state == BucketState::TAKEN && hash == map[p].hash) {
while (state[p] != BucketState::FREE) {
if (state[p] == BucketState::TAKEN && hash == map[p].hash) {
// Got it!
map[p].state = BucketState::REMOVED;
state[p] = BucketState::REMOVED;
removedCount_++;
count_--;
return true;
@@ -255,17 +256,15 @@ public:
template<class T>
void Iterate(T func) {
for (auto &iter : map) {
if (iter.state == BucketState::TAKEN) {
func(iter.hash, iter.value);
for (size_t i = 0; i < map.size(); i++) {
if (state[i] == BucketState::TAKEN) {
func(map[i].hash, map[i].value);
}
}
}
void Clear() {
// TODO: Speedup?
map.clear();
map.resize(capacity_);
memset(state.data(), (int)BucketState::FREE, state.size());
}
// Gets rid of REMOVED tombstones, making lookups somewhat more efficient.
@@ -285,23 +284,24 @@ private:
// We simply move out the existing data, then we re-insert the old.
// This is extremely non-atomic and will need synchronization.
std::vector<Pair> old = std::move(map);
std::vector<BucketState> oldState = std::move(state);
capacity_ *= factor;
map.clear();
map.resize(capacity_);
state.resize(capacity_);
count_ = 0; // Insert will update it.
removedCount_ = 0;
for (auto &iter : old) {
if (iter.state == BucketState::TAKEN) {
Insert(iter.hash, iter.value);
for (size_t i = 0; i < old.size(); i++) {
if (oldState[i] == BucketState::TAKEN) {
Insert(old[i].hash, old[i].value);
}
}
}
struct Pair {
BucketState state;
uint32_t hash;
Value value;
};
std::vector<Pair> map;
std::vector<BucketState> state;
int capacity_;
int count_ = 0;
int removedCount_ = 0;
+38 -521
View File
@@ -153,156 +153,14 @@ VulkanContext::~VulkanContext() {
VulkanFree();
}
void TransitionToPresent(VkCommandBuffer cmd, VkImage image) {
VkImageMemoryBarrier prePresentBarrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
prePresentBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
prePresentBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
prePresentBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
prePresentBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
prePresentBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
prePresentBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
prePresentBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
prePresentBarrier.subresourceRange.baseMipLevel = 0;
prePresentBarrier.subresourceRange.levelCount = 1;
prePresentBarrier.subresourceRange.baseArrayLayer = 0;
prePresentBarrier.subresourceRange.layerCount = 1;
prePresentBarrier.image = image;
vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
0, 0, nullptr, 0, nullptr, 1, &prePresentBarrier);
}
void TransitionFromPresent(VkCommandBuffer cmd, VkImage image) {
VkImageMemoryBarrier prePresentBarrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
prePresentBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
prePresentBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
prePresentBarrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
prePresentBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
prePresentBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
prePresentBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
prePresentBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
prePresentBarrier.subresourceRange.baseMipLevel = 0;
prePresentBarrier.subresourceRange.levelCount = 1;
prePresentBarrier.subresourceRange.baseArrayLayer = 0;
prePresentBarrier.subresourceRange.layerCount = 1;
prePresentBarrier.image = image;
vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
0, 0, nullptr, 0, nullptr, 1, &prePresentBarrier);
}
VkCommandBuffer VulkanContext::GetInitCommandBuffer() {
void VulkanContext::BeginFrame() {
FrameData *frame = &frame_[curFrame_];
if (!frame->hasInitCommands) {
VulkanBeginCommandBuffer(frame->cmdInit);
frame->hasInitCommands = true;
}
return frame_[curFrame_].cmdInit;
}
void VulkanContext::QueueBeforeSurfaceRender(VkCommandBuffer cmd) {
cmdQueue_.push_back(cmd);
}
VkCommandBuffer VulkanContext::BeginFrame() {
FrameData *frame = &frame_[curFrame_];
// Get the index of the next available swapchain image, and a semaphore to block command buffer execution on.
// Now, I wonder if we should do this early in the frame or late? Right now we do it early, which should be fine.
VkResult res = vkAcquireNextImageKHR(device_, swap_chain_, UINT64_MAX, acquireSemaphore_, VK_NULL_HANDLE, &current_buffer);
// TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR
// return codes
assert(res == VK_SUCCESS);
// Make sure the very last command buffer from the frame before the previous has been fully executed.
WaitAndResetFence(frame->fence);
// Process pending deletes.
frame->deleteList.PerformDeletes(device_);
// Reset both command buffers in one fell swoop.
// Note that on the first frame, there might already be commands so don't reset in that case.
if (!frame->hasInitCommands) {
vkResetCommandPool(device_, frame->cmdPool, 0);
}
VkCommandBufferBeginInfo begin = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
begin.pInheritanceInfo = nullptr;
res = vkBeginCommandBuffer(frame->cmdBuf, &begin);
TransitionFromPresent(frame->cmdBuf, swapChainBuffers[current_buffer].image);
return frame->cmdBuf;
}
VkCommandBuffer VulkanContext::BeginSurfaceRenderPass(VkClearValue clear_values[2]) {
FrameData *frame = &frame_[curFrame_];
VkRenderPassBeginInfo rp_begin = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
rp_begin.renderPass = surface_render_pass_;
rp_begin.framebuffer = framebuffers_[current_buffer];
rp_begin.renderArea.offset.x = 0;
rp_begin.renderArea.offset.y = 0;
rp_begin.renderArea.extent.width = width_;
rp_begin.renderArea.extent.height = height_;
rp_begin.clearValueCount = 2;
rp_begin.pClearValues = clear_values;
vkCmdBeginRenderPass(frame->cmdBuf, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
return frame->cmdBuf;
}
void VulkanContext::EndSurfaceRenderPass() {
FrameData *frame = &frame_[curFrame_];
// ILOG("VulkanContext::EndSurfaceRenderPass");
vkCmdEndRenderPass(frame->cmdBuf);
}
void VulkanContext::EndFrame() {
FrameData *frame = &frame_[curFrame_];
TransitionToPresent(frame->cmdBuf, swapChainBuffers[current_buffer].image);
VkResult res = vkEndCommandBuffer(frame->cmdBuf);
assert(res == VK_SUCCESS);
// So the sequence will be, cmdInit, [cmdQueue_], frame->cmdBuf.
// This way we bunch up all the initialization needed for the frame, we render to
// other buffers before the back buffer, and then last we render to the backbuffer.
int numCmdBufs = 0;
std::vector<VkCommandBuffer> cmdBufs;
if (frame->hasInitCommands) {
vkEndCommandBuffer(frame->cmdInit);
cmdBufs.push_back(frame->cmdInit);
frame->hasInitCommands = false;
}
for (auto cmd : cmdQueue_) {
cmdBufs.push_back(cmd);
}
cmdQueue_.clear();
cmdBufs.push_back(frame->cmdBuf);
VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &acquireSemaphore_;
VkPipelineStageFlags waitStage[1] = { VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT };
submit_info.pWaitDstStageMask = waitStage;
submit_info.commandBufferCount = (uint32_t)cmdBufs.size();
submit_info.pCommandBuffers = cmdBufs.data();
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &renderingCompleteSemaphore_;
res = vkQueueSubmit(gfx_queue_, 1, &submit_info, frame->fence);
assert(res == VK_SUCCESS);
VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
present.swapchainCount = 1;
present.pSwapchains = &swap_chain_;
present.pImageIndices = &current_buffer;
present.pWaitSemaphores = &renderingCompleteSemaphore_;
present.waitSemaphoreCount = 1;
present.pResults = NULL;
res = vkQueuePresentKHR(gfx_queue_, &present);
// TODO: Deal with the VK_SUBOPTIMAL_WSI and VK_ERROR_OUT_OF_DATE_WSI
// return codes
assert(!res);
frame->deleteList.Take(globalDeleteList_);
frame_[curFrame_].deleteList.Take(globalDeleteList_);
curFrame_++;
if (curFrame_ >= inflightFrames_) {
curFrame_ = 0;
@@ -330,78 +188,19 @@ bool VulkanContext::MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirem
return false;
}
void VulkanBeginCommandBuffer(VkCommandBuffer cmd) {
VkResult U_ASSERT_ONLY res;
VkCommandBufferBeginInfo cmd_buf_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
cmd_buf_info.pInheritanceInfo = nullptr;
cmd_buf_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
res = vkBeginCommandBuffer(cmd, &cmd_buf_info);
assert(res == VK_SUCCESS);
}
bool VulkanContext::InitObjects(bool depthPresent) {
int physical_device = 0; // TODO
bool VulkanContext::InitObjects() {
InitQueue();
// Create frame data
for (int i = 0; i < MAX_INFLIGHT_FRAMES; i++) {
VkResult U_ASSERT_ONLY res;
VkCommandPoolCreateInfo cmd_pool_info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
cmd_pool_info.queueFamilyIndex = graphics_queue_family_index_;
cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
res = vkCreateCommandPool(device_, &cmd_pool_info, NULL, &frame_[i].cmdPool);
assert(res == VK_SUCCESS);
VkCommandBufferAllocateInfo cmd_alloc = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
cmd_alloc.commandPool = frame_[i].cmdPool;
cmd_alloc.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
cmd_alloc.commandBufferCount = 2;
VkCommandBuffer cmdBuf[2];
res = vkAllocateCommandBuffers(device_, &cmd_alloc, cmdBuf);
assert(res == VK_SUCCESS);
frame_[i].cmdBuf = cmdBuf[0];
frame_[i].cmdInit = cmdBuf[1];
frame_[i].fence = CreateFence(true); // So it can be instantly waited on
}
VkCommandBuffer cmd = GetInitCommandBuffer();
if (!InitSwapchain(cmd)) {
if (!InitSwapchain()) {
return false;
}
InitDepthStencilBuffer(cmd);
InitSurfaceRenderPass(depthPresent, true);
InitFramebuffers(depthPresent);
// The init command buffer will be executed as part of the first frame.
return true;
}
void VulkanContext::DestroyObjects() {
for (int i = 0; i < MAX_INFLIGHT_FRAMES; i++) {
VkCommandBuffer cmdBuf[2];
cmdBuf[0] = frame_[i].cmdBuf;
cmdBuf[1] = frame_[i].cmdInit;
vkFreeCommandBuffers(device_, frame_[i].cmdPool, 2, cmdBuf);
vkDestroyCommandPool(device_, frame_[i].cmdPool, nullptr);
}
for (int i = 0; i < MAX_INFLIGHT_FRAMES; i++) {
vkDestroyFence(device_, frame_[i].fence, nullptr);
}
DestroyFramebuffers();
DestroySurfaceRenderPass();
DestroyDepthStencilBuffer();
DestroySwapChain();
// If there happen to be any pending deletes, now is a good time.
for (int i = 0; i < ARRAY_SIZE(frame_); i++) {
frame_[i].deleteList.PerformDeletes(device_);
}
Delete().PerformDeletes(device_);
if (swapchain_ != VK_NULL_HANDLE)
vkDestroySwapchainKHR(device_, swapchain_, nullptr);
swapchain_ = VK_NULL_HANDLE;
vkDestroySurfaceKHR(instance_, surface_, nullptr);
surface_ = VK_NULL_HANDLE;
@@ -692,77 +491,6 @@ void VulkanContext::DestroyDebugMsgCallback() {
}
}
void VulkanContext::InitDepthStencilBuffer(VkCommandBuffer cmd) {
VkResult U_ASSERT_ONLY res;
bool U_ASSERT_ONLY pass;
const VkFormat depth_format = deviceInfo_.preferredDepthStencilFormat;
int aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
VkImageCreateInfo image_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.format = depth_format;
image_info.extent.width = width_;
image_info.extent.height = height_;
image_info.extent.depth = 1;
image_info.mipLevels = 1;
image_info.arrayLayers = 1;
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_info.queueFamilyIndexCount = 0;
image_info.pQueueFamilyIndices = NULL;
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
image_info.flags = 0;
VkMemoryAllocateInfo mem_alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
mem_alloc.allocationSize = 0;
mem_alloc.memoryTypeIndex = 0;
VkMemoryRequirements mem_reqs;
depth.format = depth_format;
res = vkCreateImage(device_, &image_info, NULL, &depth.image);
assert(res == VK_SUCCESS);
vkGetImageMemoryRequirements(device_, depth.image, &mem_reqs);
mem_alloc.allocationSize = mem_reqs.size;
/* Use the memory properties to determine the type of memory required */
pass = MemoryTypeFromProperties(mem_reqs.memoryTypeBits,
0, /* No requirements */
&mem_alloc.memoryTypeIndex);
assert(pass);
res = vkAllocateMemory(device_, &mem_alloc, NULL, &depth.mem);
assert(res == VK_SUCCESS);
res = vkBindImageMemory(device_, depth.image, depth.mem, 0);
assert(res == VK_SUCCESS);
TransitionImageLayout(cmd, depth.image,
aspectMask,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
VkImageViewCreateInfo depth_view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
depth_view_info.image = depth.image;
depth_view_info.format = depth_format;
depth_view_info.components.r = VK_COMPONENT_SWIZZLE_R;
depth_view_info.components.g = VK_COMPONENT_SWIZZLE_G;
depth_view_info.components.b = VK_COMPONENT_SWIZZLE_B;
depth_view_info.components.a = VK_COMPONENT_SWIZZLE_A;
depth_view_info.subresourceRange.aspectMask = aspectMask;
depth_view_info.subresourceRange.baseMipLevel = 0;
depth_view_info.subresourceRange.levelCount = 1;
depth_view_info.subresourceRange.baseArrayLayer = 0;
depth_view_info.subresourceRange.layerCount = 1;
depth_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
depth_view_info.flags = 0;
res = vkCreateImageView(device_, &depth_view_info, NULL, &depth.view);
assert(res == VK_SUCCESS);
}
#ifdef _WIN32
void VulkanContext::InitSurfaceWin32(HINSTANCE conn, HWND wnd) {
connection = conn;
@@ -876,39 +604,32 @@ void VulkanContext::InitQueue() {
// supported format will be returned.
if (formatCount == 0 || (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED)) {
ILOG("swapchain_format: Falling back to B8G8R8A8_UNORM");
swapchain_format = VK_FORMAT_B8G8R8A8_UNORM;
swapchainFormat_ = VK_FORMAT_B8G8R8A8_UNORM;
} else {
swapchain_format = VK_FORMAT_UNDEFINED;
swapchainFormat_ = VK_FORMAT_UNDEFINED;
for (uint32_t i = 0; i < formatCount; ++i) {
if (surfFormats[i].colorSpace != VK_COLORSPACE_SRGB_NONLINEAR_KHR) {
continue;
}
if (surfFormats[i].format == VK_FORMAT_B8G8R8A8_UNORM || surfFormats[i].format == VK_FORMAT_R8G8B8A8_UNORM) {
swapchain_format = surfFormats[i].format;
swapchainFormat_ = surfFormats[i].format;
break;
}
}
if (swapchain_format == VK_FORMAT_UNDEFINED) {
if (swapchainFormat_ == VK_FORMAT_UNDEFINED) {
// Okay, take the first one then.
swapchain_format = surfFormats[0].format;
swapchainFormat_ = surfFormats[0].format;
}
ILOG("swapchain_format: %d (/%d)", swapchain_format, formatCount);
ILOG("swapchain_format: %d (/%d)", swapchainFormat_, formatCount);
}
delete[] surfFormats;
vkGetDeviceQueue(device_, graphics_queue_family_index_, 0, &gfx_queue_);
ILOG("gfx_queue_: %p", gfx_queue_);
VkSemaphoreCreateInfo semaphoreCreateInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
semaphoreCreateInfo.flags = 0;
res = vkCreateSemaphore(device_, &semaphoreCreateInfo, nullptr, &acquireSemaphore_);
assert(res == VK_SUCCESS);
res = vkCreateSemaphore(device_, &semaphoreCreateInfo, nullptr, &renderingCompleteSemaphore_);
assert(res == VK_SUCCESS);
}
bool VulkanContext::InitSwapchain(VkCommandBuffer cmd) {
bool VulkanContext::InitSwapchain() {
VkResult U_ASSERT_ONLY res;
VkSurfaceCapabilitiesKHR surfCapabilities;
@@ -988,7 +709,7 @@ bool VulkanContext::InitSwapchain(VkCommandBuffer cmd) {
VkSwapchainCreateInfoKHR swap_chain_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
swap_chain_info.surface = surface_;
swap_chain_info.minImageCount = desiredNumberOfSwapChainImages;
swap_chain_info.imageFormat = swapchain_format;
swap_chain_info.imageFormat = swapchainFormat_;
swap_chain_info.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
swap_chain_info.imageExtent.width = swapChainExtent.width;
swap_chain_info.imageExtent.height = swapChainExtent.height;
@@ -1009,140 +730,15 @@ bool VulkanContext::InitSwapchain(VkCommandBuffer cmd) {
swap_chain_info.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
}
res = vkCreateSwapchainKHR(device_, &swap_chain_info, NULL, &swap_chain_);
res = vkCreateSwapchainKHR(device_, &swap_chain_info, NULL, &swapchain_);
assert(res == VK_SUCCESS);
if (res != VK_SUCCESS) {
return false;
}
res = vkGetSwapchainImagesKHR(device_, swap_chain_, &swapchainImageCount, nullptr);
assert(res == VK_SUCCESS);
ILOG("Vulkan swapchain image count: %d", swapchainImageCount);
VkImage* swapchainImages = new VkImage[swapchainImageCount];
assert(swapchainImages);
res = vkGetSwapchainImagesKHR(device_, swap_chain_, &swapchainImageCount, swapchainImages);
assert(res == VK_SUCCESS);
for (uint32_t i = 0; i < swapchainImageCount; i++) {
swap_chain_buffer sc_buffer;
VkImageViewCreateInfo color_image_view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
color_image_view.format = swapchain_format;
color_image_view.components.r = VK_COMPONENT_SWIZZLE_R;
color_image_view.components.g = VK_COMPONENT_SWIZZLE_G;
color_image_view.components.b = VK_COMPONENT_SWIZZLE_B;
color_image_view.components.a = VK_COMPONENT_SWIZZLE_A;
color_image_view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
color_image_view.subresourceRange.baseMipLevel = 0;
color_image_view.subresourceRange.levelCount = 1;
color_image_view.subresourceRange.baseArrayLayer = 0;
color_image_view.subresourceRange.layerCount = 1;
color_image_view.viewType = VK_IMAGE_VIEW_TYPE_2D;
color_image_view.flags = 0;
sc_buffer.image = swapchainImages[i];
// TODO: Pre-set them to PRESENT_SRC_KHR, as the first thing we do after acquiring
// in image to render to will be to transition them away from that.
TransitionImageLayout(cmd, sc_buffer.image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
color_image_view.image = sc_buffer.image;
res = vkCreateImageView(device_, &color_image_view, NULL, &sc_buffer.view);
swapChainBuffers.push_back(sc_buffer);
assert(res == VK_SUCCESS);
}
delete[] swapchainImages;
current_buffer = 0;
return true;
}
void VulkanContext::InitSurfaceRenderPass(bool include_depth, bool clear) {
// Need attachments for render target and depth buffer
VkAttachmentDescription attachments[2]{};
attachments[0].format = swapchain_format;
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[0].loadOp = clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments[0].flags = 0;
if (include_depth) {
attachments[1].format = depth.format;
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[1].loadOp = clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[1].stencilLoadOp = clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachments[1].flags = 0;
}
VkAttachmentReference color_reference{};
color_reference.attachment = 0;
color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference depth_reference{};
depth_reference.attachment = 1;
depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.flags = 0;
subpass.inputAttachmentCount = 0;
subpass.pInputAttachments = nullptr;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &color_reference;
subpass.pResolveAttachments = nullptr;
subpass.pDepthStencilAttachment = include_depth ? &depth_reference : nullptr;
subpass.preserveAttachmentCount = 0;
subpass.pPreserveAttachments = nullptr;
VkRenderPassCreateInfo rp_info{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
rp_info.attachmentCount = include_depth ? 2 : 1;
rp_info.pAttachments = attachments;
rp_info.subpassCount = 1;
rp_info.pSubpasses = &subpass;
rp_info.dependencyCount = 0;
rp_info.pDependencies = nullptr;
VkResult U_ASSERT_ONLY res = vkCreateRenderPass(device_, &rp_info, nullptr, &surface_render_pass_);
assert(res == VK_SUCCESS);
}
void VulkanContext::InitFramebuffers(bool include_depth) {
VkResult U_ASSERT_ONLY res;
VkImageView attachments[2];
attachments[1] = depth.view;
ILOG("InitFramebuffers: %dx%d", width_, height_);
VkFramebufferCreateInfo fb_info{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
fb_info.renderPass = surface_render_pass_;
fb_info.attachmentCount = include_depth ? 2 : 1;
fb_info.pAttachments = attachments;
fb_info.width = width_;
fb_info.height = height_;
fb_info.layers = 1;
framebuffers_.resize(swapchainImageCount);
for (uint32_t i = 0; i < swapchainImageCount; i++) {
attachments[0] = swapChainBuffers[i].view;
res = vkCreateFramebuffer(device_, &fb_info, nullptr, &framebuffers_[i]);
assert(res == VK_SUCCESS);
}
}
VkFence VulkanContext::CreateFence(bool presignalled) {
VkFence fence;
VkFenceCreateInfo fenceInfo{ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
@@ -1151,57 +747,20 @@ VkFence VulkanContext::CreateFence(bool presignalled) {
return fence;
}
void VulkanContext::WaitAndResetFence(VkFence fence) {
vkWaitForFences(device_, 1, &fence, true, UINT64_MAX);
vkResetFences(device_, 1, &fence);
}
void VulkanContext::DestroyDepthStencilBuffer() {
if (depth.view != VK_NULL_HANDLE)
vkDestroyImageView(device_, depth.view, nullptr);
if (depth.image != VK_NULL_HANDLE)
vkDestroyImage(device_, depth.image, nullptr);
if (depth.mem != VK_NULL_HANDLE)
vkFreeMemory(device_, depth.mem, nullptr);
depth.view = VK_NULL_HANDLE;
depth.image = VK_NULL_HANDLE;
depth.mem = VK_NULL_HANDLE;
}
void VulkanContext::DestroySwapChain() {
for (uint32_t i = 0; i < swapchainImageCount; i++) {
vkDestroyImageView(device_, swapChainBuffers[i].view, nullptr);
}
if (swap_chain_ != VK_NULL_HANDLE)
vkDestroySwapchainKHR(device_, swap_chain_, nullptr);
swap_chain_ = VK_NULL_HANDLE;
swapChainBuffers.clear();
vkDestroySemaphore(device_, acquireSemaphore_, nullptr);
vkDestroySemaphore(device_, renderingCompleteSemaphore_, nullptr);
}
void VulkanContext::DestroyFramebuffers() {
for (uint32_t i = 0; i < framebuffers_.size(); i++) {
vkDestroyFramebuffer(device_, framebuffers_[i], nullptr);
}
framebuffers_.clear();
}
void VulkanContext::DestroySurfaceRenderPass() {
if (surface_render_pass_ != VK_NULL_HANDLE)
vkDestroyRenderPass(device_, surface_render_pass_, nullptr);
surface_render_pass_ = VK_NULL_HANDLE;
}
void VulkanContext::DestroyDevice() {
// If there happen to be any pending deletes, now is a good time.
for (int i = 0; i < ARRAY_SIZE(frame_); i++) {
frame_[i].deleteList.PerformDeletes(device_);
}
Delete().PerformDeletes(device_);
vkDestroyDevice(device_, nullptr);
device_ = nullptr;
}
VkPipelineCache VulkanContext::CreatePipelineCache() {
VkPipelineCache cache;
VkPipelineCacheCreateInfo pc = { VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
pc.pInitialData = nullptr;
pc.initialDataSize = 0;
pc.flags = 0;
@@ -1211,7 +770,7 @@ VkPipelineCache VulkanContext::CreatePipelineCache() {
}
bool VulkanContext::CreateShaderModule(const std::vector<uint32_t> &spirv, VkShaderModule *shaderModule) {
VkShaderModuleCreateInfo sm = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
VkShaderModuleCreateInfo sm{ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
sm.pCode = spirv.data();
sm.codeSize = spirv.size() * sizeof(uint32_t);
sm.flags = 0;
@@ -1223,67 +782,25 @@ bool VulkanContext::CreateShaderModule(const std::vector<uint32_t> &spirv, VkSha
}
}
void TransitionImageLayout(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask, VkImageLayout old_image_layout, VkImageLayout new_image_layout) {
VkImageMemoryBarrier image_memory_barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
image_memory_barrier.srcAccessMask = 0;
image_memory_barrier.dstAccessMask = 0;
image_memory_barrier.oldLayout = old_image_layout;
image_memory_barrier.newLayout = new_image_layout;
void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask,
VkImageLayout oldImageLayout, VkImageLayout newImageLayout,
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) {
VkImageMemoryBarrier image_memory_barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
image_memory_barrier.srcAccessMask = srcAccessMask;
image_memory_barrier.dstAccessMask = dstAccessMask;
image_memory_barrier.oldLayout = oldImageLayout;
image_memory_barrier.newLayout = newImageLayout;
image_memory_barrier.image = image;
image_memory_barrier.subresourceRange.aspectMask = aspectMask;
image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = 1;
image_memory_barrier.subresourceRange.layerCount = 1;
if (old_image_layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
image_memory_barrier.srcAccessMask |= VK_ACCESS_MEMORY_READ_BIT;
}
if (old_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
image_memory_barrier.srcAccessMask |= VK_ACCESS_SHADER_READ_BIT;
}
if (old_image_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
image_memory_barrier.srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
}
if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
if (old_image_layout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
image_memory_barrier.srcAccessMask |= VK_ACCESS_HOST_WRITE_BIT;
}
image_memory_barrier.dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT;
}
if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
/* Make sure anything that was copying from this image has completed */
image_memory_barrier.dstAccessMask |= VK_ACCESS_TRANSFER_WRITE_BIT;
}
if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
/* Make sure any Copy or CPU writes to image are flushed */
if (old_image_layout != VK_IMAGE_LAYOUT_UNDEFINED) {
image_memory_barrier.srcAccessMask |= VK_ACCESS_TRANSFER_WRITE_BIT;
}
image_memory_barrier.dstAccessMask |= VK_ACCESS_SHADER_READ_BIT;
}
if (new_image_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
image_memory_barrier.dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
}
if (new_image_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
image_memory_barrier.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
}
if (new_image_layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
image_memory_barrier.dstAccessMask |= VK_ACCESS_MEMORY_READ_BIT;
}
VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
vkCmdPipelineBarrier(cmd, src_stages, dest_stages, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
image_memory_barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkCmdPipelineBarrier(cmd, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
EShLanguage FindLanguage(const VkShaderStageFlagBits shader_type) {
switch (shader_type) {
case VK_SHADER_STAGE_VERTEX_BIT:
+28 -80
View File
@@ -195,8 +195,7 @@ private:
std::vector<Callback> callbacks_;
};
// VulkanContext sets up the basics necessary for rendering to a window, including framebuffers etc.
// Optionally, it can create a depth buffer for you as well.
// VulkanContext manages the device and swapchain, and deferred deletion of objects.
class VulkanContext {
public:
VulkanContext();
@@ -227,19 +226,12 @@ public:
void ReinitSurfaceAndroid(int width, int height);
#endif
void InitQueue();
bool InitObjects(bool depthPresent);
bool InitSwapchain(VkCommandBuffer cmd);
void InitSurfaceRenderPass(bool include_depth, bool clear);
void InitFramebuffers(bool include_depth);
void InitDepthStencilBuffer(VkCommandBuffer cmd);
bool InitObjects();
bool InitSwapchain();
// Also destroys the surface.
void DestroyObjects();
void DestroySurfaceRenderPass();
void DestroyFramebuffers();
void DestroySwapChain();
void DestroyDepthStencilBuffer();
void DestroyDevice();
void WaitUntilQueueIdle();
@@ -248,41 +240,17 @@ public:
VkFence CreateFence(bool presignalled);
bool CreateShaderModule(const std::vector<uint32_t> &spirv, VkShaderModule *shaderModule);
void WaitAndResetFence(VkFence fence);
int GetBackbufferWidth() { return width_; }
int GetBackbufferHeight() { return height_; }
int GetWidth() { return width_; }
int GetHeight() { return height_; }
VkCommandBuffer GetInitCommandBuffer();
VkFramebuffer GetSurfaceFramebuffer() {
return framebuffers_[current_buffer];
}
// This must only be accessed between BeginSurfaceRenderPass and EndSurfaceRenderPass.
VkCommandBuffer GetSurfaceCommandBuffer() {
return frame_[curFrame_].cmdBuf;
}
VkCommandBuffer BeginFrame();
// The surface render pass is special because it has to acquire the backbuffer, and may thus "block".
// Use the returned command buffer to enqueue commands that render to the backbuffer.
// To render to other buffers first, you can submit additional commandbuffers using QueueBeforeSurfaceRender(cmd).
VkCommandBuffer BeginSurfaceRenderPass(VkClearValue clear_values[2]);
// May eventually need the ability to break and resume the backbuffer render pass in a few rare cases.
void EndSurfaceRenderPass();
void BeginFrame();
void EndFrame();
void QueueBeforeSurfaceRender(VkCommandBuffer cmd);
bool MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex);
VkResult InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFunc, int bits, void *userdata = nullptr);
void DestroyDebugMsgCallback();
VkRenderPass GetSurfaceRenderPass() const {
return surface_render_pass_;
}
VkPhysicalDevice GetPhysicalDevice(int n = 0) const {
return physical_devices_[n];
}
@@ -327,8 +295,21 @@ public:
return inflightFrames_;
}
int GetCurFrame() const {
return curFrame_;
}
VkSwapchainKHR GetSwapchain() const {
return swapchain_;
}
VkFormat GetSwapchainFormat() const {
return swapchainFormat_;
}
// 1 for no frame overlap and thus minimal latency but worst performance.
// 2 is an OK compromise, while 3 performs best but risks slightly higher latency.
enum {
MAX_INFLIGHT_FRAMES = 2,
MAX_INFLIGHT_FRAMES = 3,
};
private:
@@ -340,9 +321,6 @@ private:
bool CheckLayers(const std::vector<LayerProperties> &layer_props, const std::vector<const char *> &layer_names) const;
VkSemaphore acquireSemaphore_;
VkSemaphore renderingCompleteSemaphore_;
#ifdef _WIN32
HINSTANCE connection = nullptr; // hInstance - Windows Instance
HWND window = nullptr; // hWnd - window handle
@@ -380,36 +358,15 @@ private:
// Custom collection of things that are good to know
VulkanPhysicalDeviceInfo deviceInfo_;
struct swap_chain_buffer {
VkImage image;
VkImageView view;
};
// Swap chain
int width_ = 0;
int height_ = 0;
int flags_ = 0;
VkFormat swapchain_format = VK_FORMAT_UNDEFINED;
std::vector<VkFramebuffer> framebuffers_;
uint32_t swapchainImageCount = 0;
VkSwapchainKHR swap_chain_ = VK_NULL_HANDLE;
std::vector<swap_chain_buffer> swapChainBuffers;
int inflightFrames_ = MAX_INFLIGHT_FRAMES;
// Manages flipping command buffers for the backbuffer render pass.
// It is recommended to do the same for other rendering passes.
struct FrameData {
FrameData() : hasInitCommands(false), cmdInit(nullptr), cmdBuf(nullptr) {}
VkFence fence;
bool hasInitCommands;
// TODO: Move to frame data
VkCommandPool cmdPool;
VkCommandBuffer cmdInit;
VkCommandBuffer cmdBuf;
FrameData() {}
VulkanDeleteList deleteList;
};
FrameData frame_[MAX_INFLIGHT_FRAMES];
@@ -421,15 +378,9 @@ private:
std::vector<VkDebugReportCallbackEXT> msg_callbacks;
struct {
VkFormat format;
VkImage image = VK_NULL_HANDLE;
VkDeviceMemory mem = VK_NULL_HANDLE;
VkImageView view = VK_NULL_HANDLE;
} depth;
VkSwapchainKHR swapchain_;
VkFormat swapchainFormat_;
VkRenderPass surface_render_pass_ = VK_NULL_HANDLE;
uint32_t current_buffer = 0;
uint32_t queue_count = 0;
VkPhysicalDeviceFeatures featuresAvailable_;
@@ -438,14 +389,11 @@ private:
std::vector<VkCommandBuffer> cmdQueue_;
};
// Stand-alone utility functions
void VulkanBeginCommandBuffer(VkCommandBuffer cmd);
void TransitionImageLayout(
VkCommandBuffer cmd,
VkImage image,
VkImageAspectFlags aspectMask,
VkImageLayout old_image_layout,
VkImageLayout new_image_layout);
// Detailed control.
void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask,
VkImageLayout oldImageLayout, VkImageLayout newImageLayout,
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask);
// GLSL compiler
void init_glslang();
+36 -48
View File
@@ -8,13 +8,6 @@ VkResult VulkanTexture::Create(int w, int h, VkFormat format) {
VkFormatProperties formatProps;
vkGetPhysicalDeviceFormatProperties(vulkan_->GetPhysicalDevice(), format, &formatProps);
// See if we can use a linear tiled image for a texture, if not, we will need a staging image for the texture data.
// Linear tiling is usually only supported for 2D non-array textures.
// needStaging = (!(formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) ? true : false;
// Always stage.
needStaging = true;
return VK_SUCCESS;
}
@@ -39,7 +32,7 @@ void VulkanTexture::CreateMappableImage() {
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_LINEAR;
image_create_info.usage = needStaging ? VK_IMAGE_USAGE_TRANSFER_SRC_BIT : VK_IMAGE_USAGE_SAMPLED_BIT;
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
image_create_info.queueFamilyIndexCount = 0;
image_create_info.pQueueFamilyIndices = NULL;
image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
@@ -91,22 +84,13 @@ uint8_t *VulkanTexture::Lock(int level, int *rowPitch) {
return (uint8_t *)data;
}
void VulkanTexture::Unlock() {
void VulkanTexture::Unlock(VkCommandBuffer cmd) {
vkUnmapMemory(vulkan_->GetDevice(), mappableMemory);
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
// if we already have an image, queue it for destruction and forget it.
Wipe();
if (!needStaging) {
// If we can use the linear tiled image as a texture, just do it
image = mappableImage;
mem = mappableMemory;
TransitionImageLayout(cmd, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
// Make sure we don't accidentally delete the main image.
mappableImage = VK_NULL_HANDLE;
mappableMemory = VK_NULL_HANDLE;
} else {
{ // Shrink the diff by not unindenting. If you make major changes, remove this.
VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = format_;
@@ -145,15 +129,17 @@ void VulkanTexture::Unlock() {
assert(res == VK_SUCCESS);
// Since we're going to blit from the mappable image, set its layout to SOURCE_OPTIMAL
TransitionImageLayout(cmd, mappableImage,
TransitionImageLayout2(cmd, mappableImage,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_PREINITIALIZED,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
TransitionImageLayout(cmd, image,
TransitionImageLayout2(cmd, image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, VK_ACCESS_TRANSFER_WRITE_BIT);
VkImageCopy copy_region;
copy_region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@@ -183,10 +169,11 @@ void VulkanTexture::Unlock() {
assert(res == VK_SUCCESS);
// Set the layout for the texture image from DESTINATION_OPTIMAL to SHADER_READ_ONLY
TransitionImageLayout(cmd, image,
TransitionImageLayout2(cmd, image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
// Then drop the temporary mappable image - although should not be necessary...
vulkan_->Delete().QueueDeleteImage(mappableImage);
@@ -238,11 +225,9 @@ static bool IsDepthStencilFormat(VkFormat format) {
}
}
bool VulkanTexture::CreateDirect(int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, const VkComponentMapping *mapping) {
bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, const VkComponentMapping *mapping) {
Wipe();
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
tex_width = w;
tex_height = h;
numMips_ = numMips;
@@ -276,7 +261,19 @@ bool VulkanTexture::CreateDirect(int w, int h, int numMips, VkFormat format, VkI
// Write a command to transition the image to the requested layout, if it's not already that layout.
if (initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && initialLayout != VK_IMAGE_LAYOUT_PREINITIALIZED) {
TransitionImageLayout(cmd, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, initialLayout);
switch (initialLayout) {
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
TransitionImageLayout2(cmd, image, VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, VK_ACCESS_TRANSFER_WRITE_BIT);
break;
default:
// If you planned to use UploadMip, you want VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL. After the
// upload, you can transition.
assert(false);
break;
}
}
vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs);
@@ -337,7 +334,7 @@ bool VulkanTexture::CreateDirect(int w, int h, int numMips, VkFormat format, VkI
return true;
}
void VulkanTexture::UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength) {
void VulkanTexture::UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength) {
VkBufferImageCopy copy_region = {};
copy_region.bufferOffset = offset;
copy_region.bufferRowLength = (uint32_t)rowLength;
@@ -350,24 +347,15 @@ void VulkanTexture::UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buf
copy_region.imageSubresource.baseArrayLayer = 0;
copy_region.imageSubresource.layerCount = 1;
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
vkCmdCopyBufferToImage(cmd, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy_region);
}
void VulkanTexture::EndCreate() {
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
TransitionImageLayout(cmd, image,
void VulkanTexture::EndCreate(VkCommandBuffer cmd) {
TransitionImageLayout2(cmd, image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
void VulkanTexture::TransitionForUpload() {
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
TransitionImageLayout(cmd, image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
}
void VulkanTexture::Destroy() {
+5 -8
View File
@@ -11,7 +11,7 @@ public:
VulkanTexture(VulkanContext *vulkan, VulkanDeviceAllocator *allocator = nullptr)
: vulkan_(vulkan), image(VK_NULL_HANDLE), mem(VK_NULL_HANDLE), view(VK_NULL_HANDLE),
tex_width(0), tex_height(0), numMips_(1), format_(VK_FORMAT_UNDEFINED),
mappableImage(VK_NULL_HANDLE), mappableMemory(VK_NULL_HANDLE), needStaging(false),
mappableImage(VK_NULL_HANDLE), mappableMemory(VK_NULL_HANDLE),
allocator_(allocator), offset_(0) {
memset(&mem_reqs, 0, sizeof(mem_reqs));
}
@@ -26,16 +26,14 @@ public:
// been called.
VkResult Create(int w, int h, VkFormat format);
uint8_t *Lock(int level, int *rowPitch);
void Unlock();
void Unlock(VkCommandBuffer cmd);
// Fast uploads from buffer. Mipmaps supported.
// Usage must at least include VK_IMAGE_USAGE_TRANSFER_DST_BIT in order to use UploadMip.
// When using UploadMip, initialLayout should be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL.
bool CreateDirect(int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, const VkComponentMapping *mapping = nullptr);
void UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength); // rowLength is in pixels
void EndCreate();
void TransitionForUpload();
bool CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, const VkComponentMapping *mapping = nullptr);
void UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength); // rowLength is in pixels
void EndCreate(VkCommandBuffer cmd);
int GetNumMips() const { return numMips_; }
void Destroy();
@@ -64,5 +62,4 @@ private:
VkMemoryRequirements mem_reqs;
VulkanDeviceAllocator *allocator_;
size_t offset_;
bool needStaging;
};
+7 -1
View File
@@ -47,10 +47,16 @@ bool VulkanPushBuffer::AddBuffer() {
return false;
}
// Make validation happy.
VkMemoryRequirements reqs;
vkGetBufferMemoryRequirements(device_, info.buffer, &reqs);
// TODO: We really should use memoryTypeIndex here..
// Okay, that's the buffer. Now let's allocate some memory for it.
VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
// TODO: Should check here that memoryTypeIndex_ matches reqs.memoryTypeBits.
alloc.memoryTypeIndex = memoryTypeIndex_;
alloc.allocationSize = size_;
alloc.allocationSize = reqs.size;
res = vkAllocateMemory(device_, &alloc, nullptr, &info.deviceMemory);
if (VK_SUCCESS != res) {
+4 -1
View File
@@ -236,7 +236,10 @@
<ClCompile Include="FileSystems\VirtualDiscFileSystem.cpp" />
<ClCompile Include="Font\PGF.cpp" />
<ClCompile Include="HDRemaster.cpp" />
<ClCompile Include="HLE\HLE.cpp" />
<ClCompile Include="HLE\HLE.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
<ClCompile Include="HLE\HLEHelperThread.cpp" />
<ClCompile Include="HLE\HLETables.cpp" />
<ClCompile Include="HLE\proAdhoc.cpp" />
+10 -4
View File
@@ -35,6 +35,9 @@ const static u32 GAMEDATA_BYTES_PER_READ = 32768;
// If this is too high, some games (e.g. Senjou no Valkyria 3) will lag.
const static u32 GAMEDATA_READS_PER_UPDATE = 20;
const u32 ERROR_UTILITY_GAMEDATA_MEMSTRICK_WRITE_PROTECTED = 0x80111903;
const u32 ERROR_UTILITY_GAMEDATA_MEMSTRICK_REMOVED = 0x80111901;
static const std::string SFO_FILENAME = "PARAM.SFO";
namespace
@@ -95,6 +98,9 @@ int PSPGamedataInstallDialog::Init(u32 paramAddr) {
int PSPGamedataInstallDialog::Update(int animSpeed) {
if (GetStatus() != SCE_UTILITY_STATUS_RUNNING)
return SCE_ERROR_UTILITY_INVALID_STATUS;
// TODO: This should return error codes in some cases, like write failure.
// request.common.result must be updated for errors as well.
if (readFiles < numFiles) {
if (currentInputFile != 0 && currentOutputFile != 0) {
@@ -244,7 +250,7 @@ void PSPGamedataInstallDialog::UpdateProgress() {
}
void PSPGamedataInstallDialog::DoState(PointerWrap &p) {
auto s = p.Section("PSPGamedataInstallDialog", 0, 3);
auto s = p.Section("PSPGamedataInstallDialog", 0, 4);
if (!s)
return;
@@ -252,8 +258,8 @@ void PSPGamedataInstallDialog::DoState(PointerWrap &p) {
PSPDialog::DoState(p);
p.Do(request);
// This was included in version 2 and higher.
if (s > 2) {
// This was included in version 2 and higher, but for BC reasons we use 3+.
if (s >= 3) {
p.Do(param.ptr);
p.Do(inFileNames);
p.Do(numFiles);
@@ -265,7 +271,7 @@ void PSPGamedataInstallDialog::DoState(PointerWrap &p) {
param.ptr = 0;
}
if (s > 3) {
if (s >= 4) {
p.Do(currentInputFile);
p.Do(currentInputBytesLeft);
p.Do(currentOutputFile);
+87 -31
View File
@@ -143,6 +143,18 @@ static const wchar_t oskKeys[OSK_KEYBOARD_COUNT][5][14] =
},
};
// This isn't a complete representation of these flags, it just helps ensure we show the right keyboards.
int allowedInputFlagsMap[OSK_KEYBOARD_COUNT] = {
PSP_UTILITY_OSK_INPUTTYPE_LATIN_LOWERCASE | PSP_UTILITY_OSK_INPUTTYPE_LATIN_SYMBOL | PSP_UTILITY_OSK_INPUTTYPE_LATIN_DIGIT,
PSP_UTILITY_OSK_INPUTTYPE_LATIN_UPPERCASE | PSP_UTILITY_OSK_INPUTTYPE_LATIN_SYMBOL,
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_HIRAGANA,
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_KATAKANA | PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_HALF_KATAKANA,
PSP_UTILITY_OSK_INPUTTYPE_KOREAN,
PSP_UTILITY_OSK_INPUTTYPE_RUSSIAN_LOWERCASE,
PSP_UTILITY_OSK_INPUTTYPE_RUSSIAN_UPPERCASE,
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_LOWERCASE | PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_SYMBOL | PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_DIGIT,
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_UPPERCASE | PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_SYMBOL,
};
PSPOskDialog::PSPOskDialog() : PSPDialog() {
// This can break all kinds of stuff, changing the decimal point in sprintf for example.
@@ -227,6 +239,42 @@ void PSPOskDialog::ConvertUCS2ToUTF8(std::string& _string, const wchar_t *input)
_string = stringBuffer;
}
static void FindValidKeyboard(s32 inputType, int direction, OskKeyboardLanguage &lang, OskKeyboardDisplay &disp) {
OskKeyboardLanguage origLang = lang;
OskKeyboardDisplay origDisp = disp;
if (inputType == 0) {
return;
}
// TODO: Limit by allowed keyboards properly... this is just an approximation.
int tries = OSK_LANGUAGE_COUNT * 2;
while (!(inputType & allowedInputFlagsMap[disp]) && tries > 0) {
if ((--tries % 1) == 0) {
lang = (OskKeyboardLanguage)((OSK_LANGUAGE_COUNT + lang + direction) % OSK_LANGUAGE_COUNT);
disp = OskKeyboardCases[lang][LOWERCASE];
} else {
disp = OskKeyboardCases[lang][UPPERCASE];
}
}
if (tries == 0) {
// In case of error, let's just fall back to allowing all.
lang = origLang;
disp = origDisp;
}
}
static bool IsKeyboardShiftValid(s32 inputType, OskKeyboardLanguage lang, OskKeyboardDisplay disp) {
// Swap disp and check if it's valid.
if (disp == OskKeyboardCases[lang][UPPERCASE])
disp = OskKeyboardCases[lang][LOWERCASE];
else
disp = OskKeyboardCases[lang][UPPERCASE];
return inputType == 0 || (inputType & allowedInputFlagsMap[disp]) != 0;
}
int PSPOskDialog::Init(u32 oskPtr) {
// Ignore if already running
if (GetStatus() != SCE_UTILITY_STATUS_NONE) {
@@ -259,8 +307,9 @@ int PSPOskDialog::Init(u32 oskPtr) {
ChangeStatusInit(OSK_INIT_DELAY_US);
selectedChar = 0;
currentKeyboard = OSK_KEYBOARD_LATIN_LOWERCASE;
currentKeyboardLanguage = OSK_LANGUAGE_ENGLISH;
currentKeyboard = OSK_KEYBOARD_LATIN_LOWERCASE;
FindValidKeyboard(oskParams->fields[0].inputtype, 1, currentKeyboardLanguage, currentKeyboard);
ConvertUCS2ToUTF8(oskDesc, oskParams->fields[0].desc);
ConvertUCS2ToUTF8(oskIntext, oskParams->fields[0].intext);
@@ -887,37 +936,43 @@ int PSPOskDialog::Update(int animSpeed) {
PPGeDrawText("Start", 135, 220, PPGE_ALIGN_LEFT, 0.6f, CalcFadedColor(0xFFFFFFFF));
PPGeDrawText(di->T("Finish"), 185, 222, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF));
int index = (currentKeyboardLanguage - 1) % OSK_LANGUAGE_COUNT;
const char *countryCode;
auto lookupLangName = [&](int direction) {
// First, find the valid one...
OskKeyboardLanguage lang = (OskKeyboardLanguage)((OSK_LANGUAGE_COUNT + currentKeyboardLanguage + direction) % OSK_LANGUAGE_COUNT);
OskKeyboardDisplay disp = OskKeyboardCases[lang][LOWERCASE];
FindValidKeyboard(oskParams->fields[0].inputtype, direction, lang, disp);
if (index >= 0)
countryCode = OskKeyboardNames[(currentKeyboardLanguage - 1) % OSK_LANGUAGE_COUNT].c_str();
else
countryCode = OskKeyboardNames[OSK_LANGUAGE_COUNT - 1].c_str();
if (lang == currentKeyboardLanguage) {
return (const char *)nullptr;
}
const char *language = languageMapping[countryCode].first.c_str();
// Now, let's grab the name.
const char *countryCode = OskKeyboardNames[lang].c_str();
const char *language = languageMapping[countryCode].first.c_str();
if (!strcmp(countryCode, "English Full-width"))
language = "English Full-width";
countryCode = OskKeyboardNames[currentKeyboardLanguage].c_str();
if (strcmp(countryCode, "ko_KR")) {
// It seems like this is a "fake" country code for extra keyboard purposes.
if (!strcmp(countryCode, "English Full-width"))
language = "English Full-width";
return language;
};
if (OskKeyboardNames[currentKeyboardLanguage] != "ko_KR" && IsKeyboardShiftValid(oskParams->fields[0].inputtype, currentKeyboardLanguage, currentKeyboard)) {
PPGeDrawText("Select", 135, 245, PPGE_ALIGN_LEFT, 0.6f, CalcFadedColor(0xFFFFFFFF));
PPGeDrawText(di->T("Shift"), 185, 247, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF));
}
PPGeDrawText("L", 235, 220, PPGE_ALIGN_LEFT, 0.6f, CalcFadedColor(0xFFFFFFFF));
PPGeDrawText(language, 255, 222, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF));
countryCode = OskKeyboardNames[(currentKeyboardLanguage + 1) % OSK_LANGUAGE_COUNT].c_str();
language = languageMapping[countryCode].first.c_str();
const char *prevLang = lookupLangName(-1);
if (prevLang) {
PPGeDrawText("L", 235, 220, PPGE_ALIGN_LEFT, 0.6f, CalcFadedColor(0xFFFFFFFF));
PPGeDrawText(prevLang, 255, 222, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF));
}
if (!strcmp(countryCode, "English Full-width"))
language = "English Full-width";
PPGeDrawText("R", 235, 245, PPGE_ALIGN_LEFT, 0.6f, CalcFadedColor(0xFFFFFFFF));
PPGeDrawText(language, 255, 247, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF));
const char *nextLang = lookupLangName(1);
if (nextLang) {
PPGeDrawText("R", 235, 245, PPGE_ALIGN_LEFT, 0.6f, CalcFadedColor(0xFFFFFFFF));
PPGeDrawText(nextLang, 255, 247, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF));
}
if (IsButtonPressed(CTRL_UP) || IsButtonHeld(CTRL_UP, upBtnFramesHeld, framesHeldThreshold, framesHeldRepeatRate)) {
selectedChar -= numKeyCols[currentKeyboard];
@@ -939,10 +994,12 @@ int PSPOskDialog::Update(int animSpeed) {
inputChars = CombinationString(true);
} else if (IsButtonPressed(CTRL_SELECT)) {
// Select now swaps case.
if (currentKeyboard == OskKeyboardCases[currentKeyboardLanguage][UPPERCASE])
currentKeyboard = OskKeyboardCases[currentKeyboardLanguage][LOWERCASE];
else
currentKeyboard = OskKeyboardCases[currentKeyboardLanguage][UPPERCASE];
if (IsKeyboardShiftValid(oskParams->fields[0].inputtype, currentKeyboardLanguage, currentKeyboard)) {
if (currentKeyboard == OskKeyboardCases[currentKeyboardLanguage][UPPERCASE])
currentKeyboard = OskKeyboardCases[currentKeyboardLanguage][LOWERCASE];
else
currentKeyboard = OskKeyboardCases[currentKeyboardLanguage][UPPERCASE];
}
if (selectedRow >= numKeyRows[currentKeyboard]) {
selectedRow = numKeyRows[currentKeyboard] - 1;
@@ -954,10 +1011,10 @@ int PSPOskDialog::Update(int animSpeed) {
selectedChar = selectedRow * numKeyCols[currentKeyboard] + selectedExtra;
} else if (IsButtonPressed(CTRL_RTRIGGER)) {
// TODO: Limit by allowed keyboards...
// RTRIGGER now cycles languages forward.
currentKeyboardLanguage = (OskKeyboardLanguage)((currentKeyboardLanguage + 1) % OSK_LANGUAGE_COUNT);
currentKeyboard = OskKeyboardCases[currentKeyboardLanguage][LOWERCASE];
FindValidKeyboard(oskParams->fields[0].inputtype, 1, currentKeyboardLanguage, currentKeyboard);
if (selectedRow >= numKeyRows[currentKeyboard]) {
selectedRow = numKeyRows[currentKeyboard] - 1;
@@ -969,14 +1026,13 @@ int PSPOskDialog::Update(int animSpeed) {
selectedChar = selectedRow * numKeyCols[currentKeyboard] + selectedExtra;
} else if (IsButtonPressed(CTRL_LTRIGGER)) {
// TODO: Limit by allowed keyboards...
// LTRIGGER now cycles languages backward.
if (currentKeyboardLanguage - 1 >= 0)
currentKeyboardLanguage = (OskKeyboardLanguage)((currentKeyboardLanguage - 1) % OSK_LANGUAGE_COUNT);
else
currentKeyboardLanguage = (OskKeyboardLanguage)(OSK_LANGUAGE_COUNT - 1);
currentKeyboard = OskKeyboardCases[currentKeyboardLanguage][LOWERCASE];
FindValidKeyboard(oskParams->fields[0].inputtype, -1, currentKeyboardLanguage, currentKeyboard);
if (selectedRow >= numKeyRows[currentKeyboard]) {
selectedRow = numKeyRows[currentKeyboard] - 1;
+54 -17
View File
@@ -903,7 +903,7 @@ int SavedataParam::BuildHash(unsigned char *output,
return 0;
}
std::string SavedataParam::GetSpaceText(u64 size)
std::string SavedataParam::GetSpaceText(u64 size, bool roundUp)
{
static const char *suffixes[] = {"B", "KB", "MB", "GB"};
char text[50];
@@ -915,7 +915,11 @@ std::string SavedataParam::GetSpaceText(u64 size)
snprintf(text, sizeof(text), "%lld %s", size, suffixes[i]);
return std::string(text);
}
size /= 1024;
if (roundUp) {
size = (size + 1023) / 1024;
} else {
size /= 1024;
}
}
snprintf(text, sizeof(text), "%llu TB", size);
@@ -936,7 +940,7 @@ int SavedataParam::GetSizes(SceUtilitySavedataParam *param)
param->msFree->clusterSize = (u32)MemoryStick_SectorSize();
param->msFree->freeClusters = (u32)(freeBytes / MemoryStick_SectorSize());
param->msFree->freeSpaceKB = (u32)(freeBytes / 0x400);
const std::string spaceTxt = SavedataParam::GetSpaceText(freeBytes);
const std::string spaceTxt = SavedataParam::GetSpaceText(freeBytes, false);
memset(param->msFree->freeSpaceStr, 0, sizeof(param->msFree->freeSpaceStr));
strncpy(param->msFree->freeSpaceStr, spaceTxt.c_str(), sizeof(param->msFree->freeSpaceStr));
}
@@ -959,7 +963,7 @@ int SavedataParam::GetSizes(SceUtilitySavedataParam *param)
// Fieldrunners expects 736 KB, even though the files add up to ~600 KB.
int total_size = param->msData->info.usedClusters * (u32)MemoryStick_SectorSize();
param->msData->info.usedSpaceKB = total_size / 0x400;
std::string spaceTxt = SavedataParam::GetSpaceText(total_size);
std::string spaceTxt = SavedataParam::GetSpaceText(total_size, true);
strncpy(param->msData->info.usedSpaceStr, spaceTxt.c_str(), sizeof(param->msData->info.usedSpaceStr));
// TODO: What does this mean, then? Seems to be the same.
@@ -1001,13 +1005,13 @@ int SavedataParam::GetSizes(SceUtilitySavedataParam *param)
param->utilityData->usedClusters = total_size / (u32)MemoryStick_SectorSize();
param->utilityData->usedSpaceKB = total_size / 0x400;
std::string spaceTxt = SavedataParam::GetSpaceText(total_size);
std::string spaceTxt = SavedataParam::GetSpaceText(total_size, true);
memset(param->utilityData->usedSpaceStr, 0, sizeof(param->utilityData->usedSpaceStr));
strncpy(param->utilityData->usedSpaceStr, spaceTxt.c_str(), sizeof(param->utilityData->usedSpaceStr));
// TODO: Maybe these are rounded to the nearest 32KB? Or something?
param->utilityData->usedSpace32KB = total_size / 0x400;
spaceTxt = SavedataParam::GetSpaceText(total_size);
spaceTxt = SavedataParam::GetSpaceText(total_size, true);
memset(param->utilityData->usedSpace32Str, 0, sizeof(param->utilityData->usedSpace32Str));
strncpy(param->utilityData->usedSpace32Str, spaceTxt.c_str(), sizeof(param->utilityData->usedSpace32Str));
}
@@ -1188,29 +1192,62 @@ bool SavedataParam::GetSize(SceUtilitySavedataParam *param)
return false;
}
std::string saveDir = savePath + GetGameName(param) + GetSaveName(param);
const std::string saveDir = savePath + GetGameName(param) + GetSaveName(param);
PSPFileInfo info = pspFileSystem.GetFileInfo(saveDir);
bool exists = info.exists;
if (param->sizeInfo.IsValid())
{
const u64 freeBytes = MemoryStick_FreeSpace();
// TODO: Read the entries and count up the size vs. existing size?
s64 overwriteBytes = 0;
s64 writeBytes = 0;
for (int i = 0; i < param->sizeInfo->numNormalEntries; ++i) {
const auto &entry = param->sizeInfo->normalEntries[i];
overwriteBytes += pspFileSystem.GetFileInfo(saveDir + "/" + entry.name).size;
writeBytes += entry.size;
}
for (int i = 0; i < param->sizeInfo->numSecureEntries; ++i) {
const auto &entry = param->sizeInfo->secureEntries[i];
overwriteBytes += pspFileSystem.GetFileInfo(saveDir + "/" + entry.name).size;
writeBytes += entry.size + 0x10;
}
param->sizeInfo->sectorSize = (int)MemoryStick_SectorSize();
param->sizeInfo->freeSectors = (int)(freeBytes / MemoryStick_SectorSize());
// TODO: Is this after the specified files? Before?
// TODO: Is this after the specified files? Probably before?
param->sizeInfo->freeKB = (int)(freeBytes / 1024);
std::string spaceTxt = SavedataParam::GetSpaceText(freeBytes);
strncpy(param->sizeInfo->freeString, spaceTxt.c_str(), 8);
param->sizeInfo->freeString[7] = '\0';
std::string spaceTxt = SavedataParam::GetSpaceText(freeBytes, false);
truncate_cpy(param->sizeInfo->freeString, spaceTxt.c_str());
// TODO.
param->sizeInfo->neededKB = 0;
strcpy(param->sizeInfo->neededString, "0 KB");
param->sizeInfo->overwriteKB = 0;
strcpy(param->sizeInfo->overwriteString, "0 KB");
if (writeBytes - overwriteBytes < (s64)freeBytes) {
param->sizeInfo->neededKB = 0;
// Note: this is "needed to overwrite".
param->sizeInfo->overwriteKB = 0;
spaceTxt = GetSpaceText(0, true);
truncate_cpy(param->sizeInfo->neededString, spaceTxt.c_str());
truncate_cpy(param->sizeInfo->overwriteString, spaceTxt.c_str());
} else {
// Bytes needed to save additional data.
s64 neededBytes = writeBytes - freeBytes;
param->sizeInfo->neededKB = (neededBytes + 1023) / 1024;
spaceTxt = GetSpaceText(neededBytes, true);
truncate_cpy(param->sizeInfo->neededString, spaceTxt.c_str());
if (writeBytes - overwriteBytes < (s64)freeBytes) {
param->sizeInfo->overwriteKB = 0;
spaceTxt = GetSpaceText(0, true);
truncate_cpy(param->sizeInfo->overwriteString, spaceTxt.c_str());
} else {
s64 neededOverwriteBytes = writeBytes - freeBytes - overwriteBytes;
param->sizeInfo->overwriteKB = (neededOverwriteBytes + 1023) / 1024;
spaceTxt = GetSpaceText(neededOverwriteBytes, true);
truncate_cpy(param->sizeInfo->overwriteString, spaceTxt.c_str());
}
}
}
return exists;
+1 -1
View File
@@ -323,7 +323,7 @@ public:
std::string GetKey(const SceUtilitySavedataParam *param) const;
bool HasKey(const SceUtilitySavedataParam *param) const;
static std::string GetSpaceText(u64 size);
static std::string GetSpaceText(u64 size, bool roundUp);
int SetPspParam(SceUtilitySavedataParam* param);
SceUtilitySavedataParam *GetPspParam();
+2 -2
View File
@@ -44,7 +44,7 @@ void GenerateDepalShader300(char *buffer, GEBufferFormat pixelFormat, ShaderLang
WRITE(p, "layout(set = 0, binding = 0) uniform sampler2D tex;\n");
WRITE(p, "layout(set = 0, binding = 1) uniform sampler2D pal;\n");
WRITE(p, "layout(location = 0) in vec2 v_texcoord0;\n");
WRITE(p, "layout(location = 0) out vec4 fragColor0\n;");
WRITE(p, "layout(location = 0) out vec4 fragColor0;\n");
} else {
if (gl_extensions.IsGLES) {
WRITE(p, "#version 300 es\n");
@@ -288,4 +288,4 @@ void GenerateDepalShader(char *buffer, GEBufferFormat pixelFormat, ShaderLanguag
}
}
#undef WRITE
#undef WRITE
+2
View File
@@ -20,4 +20,6 @@
#include "GPU/ge_constants.h"
#include "GPU/Common/ShaderCommon.h"
static const int DEPAL_TEXTURE_OLD_AGE = 120;
void GenerateDepalShader(char *buffer, GEBufferFormat pixelFormat, ShaderLanguage language);
+4
View File
@@ -71,6 +71,10 @@ public:
void SetupVertexDecoder(u32 vertType);
bool IsCodePtrVertexDecoder(const u8 *ptr) const {
return decJitCache_->IsInSpace(ptr);
}
protected:
virtual void ClearTrackedVertexArrays() {}
+274 -8
View File
@@ -32,6 +32,7 @@
#include "Core/ELF/ParamSFO.h"
#include "Core/System.h"
#include "Core/HLE/sceDisplay.h"
#include "GPU/Common/DrawEngineCommon.h"
#include "GPU/Common/FramebufferCommon.h"
#include "GPU/Common/PostShader.h"
#include "GPU/Common/TextureCacheCommon.h"
@@ -117,6 +118,22 @@ FramebufferManagerCommon::FramebufferManagerCommon(Draw::DrawContext *draw)
}
FramebufferManagerCommon::~FramebufferManagerCommon() {
DecimateFBOs();
for (auto vfb : vfbs_) {
DestroyFramebuf(vfb);
}
vfbs_.clear();
for (auto &tempFB : tempFBOs_) {
tempFB.second.fbo->Release();
}
tempFBOs_.clear();
// Do the same for ReadFramebuffersToMemory's VFBs
for (auto vfb : bvfbs_) {
DestroyFramebuf(vfb);
}
bvfbs_.clear();
}
void FramebufferManagerCommon::Init() {
@@ -140,7 +157,7 @@ bool FramebufferManagerCommon::UpdateSize() {
void FramebufferManagerCommon::BeginFrame() {
DecimateFBOs();
currentRenderVfb_ = 0;
currentRenderVfb_ = nullptr;
updateVRAM_ = !(g_Config.iRenderingMode == FB_NON_BUFFERED_MODE || g_Config.iRenderingMode == FB_BUFFERED_MODE);
}
@@ -309,7 +326,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
bool vfbFormatChanged = false;
// Find a matching framebuffer
VirtualFramebuffer *vfb = 0;
VirtualFramebuffer *vfb = nullptr;
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *v = vfbs_[i];
if (v->fb_address == params.fb_address) {
@@ -811,7 +828,7 @@ void FramebufferManagerCommon::SetViewport2D(int x, int y, int w, int h) {
}
void FramebufferManagerCommon::CopyDisplayToOutput() {
DownloadFramebufferOnSwitch(currentRenderVfb_);
// DownloadFramebufferOnSwitch(currentRenderVfb_);
currentRenderVfb_ = 0;
@@ -1045,6 +1062,11 @@ void FramebufferManagerCommon::CopyDisplayToOutput() {
void FramebufferManagerCommon::DecimateFBOs() {
currentRenderVfb_ = 0;
for (auto iter : fbosToDelete_) {
delete iter;
}
fbosToDelete_.clear();
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *vfb = vfbs_[i];
int age = frameLastFramebufUsed_ - std::max(vfb->last_frame_render, vfb->last_frame_used);
@@ -1092,6 +1114,9 @@ void FramebufferManagerCommon::DecimateFBOs() {
void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, u16 w, u16 h, bool force, bool skipCopy) {
VirtualFramebuffer old = *vfb;
int oldWidth = vfb->bufferWidth;
int oldHeight = vfb->bufferHeight;
if (force) {
vfb->bufferWidth = w;
vfb->bufferHeight = h;
@@ -1148,14 +1173,14 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, u16 w,
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth });
if (old.fbo) {
INFO_LOG(FRAMEBUF, "Resizing FBO for %08x : %i x %i x %i", vfb->fb_address, w, h, vfb->format);
INFO_LOG(FRAMEBUF, "Resizing FBO for %08x : %d x %d x %d", vfb->fb_address, w, h, vfb->format);
if (vfb->fbo) {
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
if (!skipCopy && !g_Config.bDisableSlowFramebufEffects) {
BlitFramebuffer(vfb, 0, 0, &old, 0, 0, std::min(vfb->bufferWidth, vfb->width), std::min(vfb->height, vfb->bufferHeight), 0);
BlitFramebuffer(vfb, 0, 0, &old, 0, 0, std::min((u16)oldWidth, std::min(vfb->bufferWidth, vfb->width)), std::min((u16)oldHeight, std::min(vfb->height, vfb->bufferHeight)), 0);
}
}
delete old.fbo;
fbosToDelete_.push_back(old.fbo);
if (needGLESRebinds_) {
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP });
}
@@ -1800,8 +1825,6 @@ Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(u16 w, u16 h, Draw::FBCo
if (!fbo)
return fbo;
// TODO: Move binding out of here!
draw_->BindFramebufferAsRenderTarget(fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
const TempFBO info = { fbo, gpuStats.numFlips };
tempFBOs_[key] = info;
return fbo;
@@ -1838,3 +1861,246 @@ void FramebufferManagerCommon::ShowScreenResolution() {
host->NotifyUserMessage(messageStream.str(), 2.0f, 0xFFFFFF, "resize");
INFO_LOG(SYSTEM, "%s", messageStream.str().c_str());
}
// We might also want to implement an asynchronous callback-style version of this. Would probably
// only be possible to implement optimally on Vulkan, but on GL and D3D11 we could do pixel buffers
// and read on the next frame, then call the callback. PackFramebufferAsync_ on OpenGL already does something similar.
//
// The main use cases for this are:
// * GE debugging(in practice async will not matter because it will stall anyway.)
// * Video file recording(would probably be great if it was async.)
// * Screenshots(benefit slightly from async.)
// * Save state screenshots(could probably be async but need to manage the stall.)
bool FramebufferManagerCommon::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) {
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {
vfb = GetVFBAt(fb_address);
}
if (!vfb) {
// If there's no vfb and we're drawing there, must be memory?
buffer = GPUDebugBuffer(Memory::GetPointer(fb_address | 0x04000000), fb_stride, 512, format);
return true;
}
int w = vfb->renderWidth, h = vfb->renderHeight;
Draw::Framebuffer *bound = nullptr;
if (vfb->fbo) {
if (maxRes > 0 && vfb->renderWidth > vfb->width * maxRes) {
w = vfb->width * maxRes;
h = vfb->height * maxRes;
Draw::Framebuffer *tempFBO = GetTempFBO(w, h);
VirtualFramebuffer tempVfb = *vfb;
tempVfb.fbo = tempFBO;
tempVfb.bufferWidth = vfb->width;
tempVfb.bufferHeight = vfb->height;
tempVfb.renderWidth = w;
tempVfb.renderHeight = h;
BlitFramebuffer(&tempVfb, 0, 0, vfb, 0, 0, vfb->width, vfb->height, 0);
bound = tempFBO;
} else {
bound = vfb->fbo;
}
}
if (!useBufferedRendering_) {
// Safety check.
w = std::min(w, PSP_CoreParameter().pixelWidth);
h = std::min(h, PSP_CoreParameter().pixelHeight);
}
// TODO: Maybe should handle flipY inside CopyFramebufferToMemorySync somehow?
bool flipY = (g_Config.iGPUBackend == GPU_BACKEND_OPENGL && !useBufferedRendering_) ? true : false;
buffer.Allocate(w, h, GE_FORMAT_8888, flipY, true);
bool retval = draw_->CopyFramebufferToMemorySync(bound, Draw::FB_COLOR_BIT, 0, 0, w, h, Draw::DataFormat::R8G8B8A8_UNORM, buffer.GetData(), w);
// We may have blitted to a temp FBO.
RebindFramebuffer();
return retval;
}
bool FramebufferManagerCommon::GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) {
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {
vfb = GetVFBAt(fb_address);
}
if (!vfb) {
// If there's no vfb and we're drawing there, must be memory?
buffer = GPUDebugBuffer(Memory::GetPointer(z_address | 0x04000000), z_stride, 512, GPU_DBG_FORMAT_16BIT);
return true;
}
int w = vfb->renderWidth;
int h = vfb->renderHeight;
if (!useBufferedRendering_) {
// Safety check.
w = std::min(w, PSP_CoreParameter().pixelWidth);
h = std::min(h, PSP_CoreParameter().pixelHeight);
}
bool flipY = (g_Config.iGPUBackend == GPU_BACKEND_OPENGL && !useBufferedRendering_) ? true : false;
if (gstate_c.Supports(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) {
buffer.Allocate(w, h, GPU_DBG_FORMAT_FLOAT_DIV_256, flipY);
} else {
buffer.Allocate(w, h, GPU_DBG_FORMAT_FLOAT, flipY);
}
draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, 0, w, h, Draw::DataFormat::D32F, buffer.GetData(), w);
return true;
}
bool FramebufferManagerCommon::GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) {
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {
vfb = GetVFBAt(fb_address);
}
if (!vfb) {
// If there's no vfb and we're drawing there, must be memory?
// TODO: Actually get the stencil.
buffer = GPUDebugBuffer(Memory::GetPointer(fb_address | 0x04000000), fb_stride, 512, GPU_DBG_FORMAT_8888);
return true;
}
int w = vfb->renderWidth;
int h = vfb->renderHeight;
if (!useBufferedRendering_) {
// Safety check.
w = std::min(w, PSP_CoreParameter().pixelWidth);
h = std::min(h, PSP_CoreParameter().pixelHeight);
}
bool flipY = (g_Config.iGPUBackend == GPU_BACKEND_OPENGL && !useBufferedRendering_) ? true : false;
buffer.Allocate(w, h, GPU_DBG_FORMAT_8BIT, flipY);
if (draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_STENCIL_BIT, 0, 0, w,h, Draw::DataFormat::S8, buffer.GetData(), w)) {
return true;
} else {
buffer.Free();
return false;
}
}
bool FramebufferManagerCommon::GetOutputFramebuffer(GPUDebugBuffer &buffer) {
int w, h;
draw_->GetFramebufferDimensions(nullptr, &w, &h);
buffer.Allocate(w, h, GE_FORMAT_8888, false, true);
draw_->CopyFramebufferToMemorySync(nullptr, Draw::FB_COLOR_BIT, 0, 0, w, h, Draw::DataFormat::R8G8B8A8_UNORM, buffer.GetData(), w);
return true;
}
// This function takes an already correctly-sized framebuffer and packs it into RAM.
// Does not need to account for scaling.
// Color conversion is currently done on CPU but should theoretically be done on GPU.
// (Except using the GPU might cause problems because of various implementations'
// dithering behavior and games that expect exact colors like Danganronpa, so we
// can't entirely be rid of the CPU path.) -- unknown
void FramebufferManagerCommon::PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h) {
if (!vfb->fbo) {
ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackFramebufferSync_: vfb->fbo == 0");
return;
}
const u32 fb_address = (0x04000000) | vfb->fb_address;
Draw::DataFormat destFormat = GEFormatToThin3D(vfb->format);
const int dstBpp = (int)DataFormatSizeInBytes(destFormat);
const int dstByteOffset = (y * vfb->fb_stride + x) * dstBpp;
u8 *destPtr = Memory::GetPointer(fb_address + dstByteOffset);
// We always need to convert from the framebuffer native format.
// Right now that's always 8888.
DEBUG_LOG(G3D, "Reading framebuffer to mem, fb_address = %08x", fb_address);
draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_COLOR_BIT, x, y, w, h, destFormat, destPtr, vfb->fb_stride);
}
void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) {
// Clamp to width. Sometimes block transfers can cause this to hit.
if (x + w >= vfb->width) {
w = vfb->width - x;
}
if (vfb) {
// We'll pseudo-blit framebuffers here to get a resized version of vfb.
OptimizeDownloadRange(vfb, x, y, w, h);
if (vfb->renderWidth == vfb->width && vfb->renderHeight == vfb->height) {
// No need to blit
PackFramebufferSync_(vfb, x, y, w, h);
} else {
VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb);
BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0);
PackFramebufferSync_(nvfb, x, y, w, h);
}
textureCache_->ForgetLastTexture();
RebindFramebuffer();
}
}
void FramebufferManagerCommon::FlushBeforeCopy() {
// Flush anything not yet drawn before blitting, downloading, or uploading.
// This might be a stalled list, or unflushed before a block transfer, etc.
// TODO: It's really bad that we are calling SetRenderFramebuffer here with
// all the irrelevant state checking it'll use to decide what to do. Should
// do something more focused here.
SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
drawEngine_->DispatchFlush();
}
void FramebufferManagerCommon::DownloadFramebufferForClut(u32 fb_address, u32 loadBytes) {
VirtualFramebuffer *vfb = GetVFBAt(fb_address);
if (vfb && vfb->fb_stride != 0) {
const u32 bpp = vfb->drawnFormat == GE_FORMAT_8888 ? 4 : 2;
int x = 0;
int y = 0;
int pixels = loadBytes / bpp;
// The height will be 1 for each stride or part thereof.
int w = std::min(pixels % vfb->fb_stride, (int)vfb->width);
int h = std::min((pixels + vfb->fb_stride - 1) / vfb->fb_stride, (int)vfb->height);
// We might still have a pending draw to the fb in question, flush if so.
FlushBeforeCopy();
// No need to download if we already have it.
if (!vfb->memoryUpdated && vfb->clutUpdatedBytes < loadBytes) {
// We intentionally don't call OptimizeDownloadRange() here - we don't want to over download.
// CLUT framebuffers are often incorrectly estimated in size.
if (x == 0 && y == 0 && w == vfb->width && h == vfb->height) {
vfb->memoryUpdated = true;
}
vfb->clutUpdatedBytes = loadBytes;
// We'll pseudo-blit framebuffers here to get a resized version of vfb.
VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb);
BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0);
PackFramebufferSync_(nvfb, x, y, w, h);
textureCache_->ForgetLastTexture();
RebindFramebuffer();
}
}
}
std::vector<FramebufferInfo> FramebufferManagerCommon::GetFramebufferList() {
std::vector<FramebufferInfo> list;
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *vfb = vfbs_[i];
FramebufferInfo info;
info.fb_address = vfb->fb_address;
info.z_address = vfb->z_address;
info.format = vfb->format;
info.width = vfb->width;
info.height = vfb->height;
info.fbo = vfb->fbo;
list.push_back(info);
}
return list;
}
+33 -8
View File
@@ -25,6 +25,7 @@
#include "Core/MemMap.h"
#include "GPU/GPU.h"
#include "GPU/ge_constants.h"
#include "GPU/GPUInterface.h"
#include "thin3d/thin3d.h"
enum {
@@ -159,6 +160,21 @@ enum DrawTextureFlags {
DRAWTEX_KEEP_TEX = 2,
};
inline Draw::DataFormat GEFormatToThin3D(int geFormat) {
switch (geFormat) {
case GE_FORMAT_4444:
return Draw::DataFormat::A4R4G4B4_UNORM_PACK16;
case GE_FORMAT_5551:
return Draw::DataFormat::A1R5G5B5_UNORM_PACK16;
case GE_FORMAT_565:
return Draw::DataFormat::R5G6B5_UNORM_PACK16;
case GE_FORMAT_8888:
return Draw::DataFormat::R8G8B8A8_UNORM;
default:
return Draw::DataFormat::UNDEFINED;
}
}
namespace Draw {
class DrawContext;
}
@@ -166,6 +182,7 @@ class DrawContext;
struct GPUDebugBuffer;
class TextureCacheCommon;
class ShaderManagerCommon;
class DrawEngineCommon;
class FramebufferManagerCommon {
public:
@@ -173,7 +190,7 @@ public:
virtual ~FramebufferManagerCommon();
virtual void Init();
void BeginFrame();
virtual void BeginFrame();
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format);
void DestroyFramebuf(VirtualFramebuffer *v);
@@ -192,10 +209,13 @@ public:
FramebufferHeuristicParams inputs;
GetFramebufferHeuristicInputs(&inputs, gstate);
VirtualFramebuffer *vfb = DoSetRenderFrameBuffer(inputs, skipDrawReason);
_dbg_assert_msg_(G3D, vfb, "DoSetRenderFramebuffer must return a valid framebuffer.");
_dbg_assert_msg_(G3D, currentRenderVfb_, "DoSetRenderFramebuffer must set a valid framebuffer.");
return vfb;
}
}
virtual void RebindFramebuffer() = 0;
std::vector<FramebufferInfo> GetFramebufferList();
void CopyDisplayToOutput();
@@ -210,8 +230,9 @@ public:
bool NotifyBlockTransferBefore(u32 dstBasePtr, int dstStride, int dstX, int dstY, u32 srcBasePtr, int srcStride, int srcX, int srcY, int w, int h, int bpp, u32 skipDrawReason);
void NotifyBlockTransferAfter(u32 dstBasePtr, int dstStride, int dstX, int dstY, u32 srcBasePtr, int srcStride, int srcX, int srcY, int w, int h, int bpp, u32 skipDrawReason);
virtual void ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) = 0;
virtual void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes) = 0;
virtual void ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h);
virtual void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes);
void DrawFramebufferToOutput(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, bool applyPostShader);
void DrawPixels(VirtualFramebuffer *vfb, int dstX, int dstY, const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height);
@@ -278,12 +299,13 @@ public:
Draw::Framebuffer *GetTempFBO(u16 w, u16 h, Draw::FBColorDepth colorDepth = Draw::FBO_8888);
// Debug features
virtual bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) = 0;
virtual bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) = 0;
virtual bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) = 0;
virtual bool GetOutputFramebuffer(GPUDebugBuffer &buffer) = 0;
virtual bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes);
virtual bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer);
virtual bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer);
virtual bool GetOutputFramebuffer(GPUDebugBuffer &buffer);
protected:
virtual void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h);
virtual void SetViewport2D(int x, int y, int w, int h);
void CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int renderWidth, int renderHeight, PostShaderUniforms *uniforms);
virtual void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) = 0;
@@ -298,7 +320,7 @@ protected:
void SetNumExtraFBOs(int num);
virtual void DisableState() = 0;
virtual void FlushBeforeCopy() = 0;
void FlushBeforeCopy();
virtual void DecimateFBOs(); // keeping it virtual to let D3D do a little extra
// Used by ReadFramebufferToMemory and later framebuffer block copies
@@ -343,6 +365,7 @@ protected:
Draw::DrawContext *draw_ = nullptr;
TextureCacheCommon *textureCache_ = nullptr;
ShaderManagerCommon *shaderManager_ = nullptr;
DrawEngineCommon *drawEngine_ = nullptr;
bool needBackBufferYSwap_ = false;
u32 displayFramebufPtr_ = 0;
@@ -391,6 +414,8 @@ protected:
std::map<u64, TempFBO> tempFBOs_;
std::vector<Draw::Framebuffer *> fbosToDelete_;
// Aggressively delete unused FBOs to save gpu memory.
enum {
FBO_OLD_AGE = 5,
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include "GPU/Common/StencilCommon.h"
u8 StencilBits5551(const u8 *ptr8, u32 numPixels) {
const u32 *ptr = (const u32 *)ptr8;
for (u32 i = 0; i < numPixels / 2; ++i) {
if (ptr[i] & 0x80008000) {
return 1;
}
}
return 0;
}
u8 StencilBits4444(const u8 *ptr8, u32 numPixels) {
const u32 *ptr = (const u32 *)ptr8;
u32 bits = 0;
for (u32 i = 0; i < numPixels / 2; ++i) {
bits |= ptr[i];
}
return ((bits >> 12) & 0xF) | (bits >> 28);
}
u8 StencilBits8888(const u8 *ptr8, u32 numPixels) {
const u32 *ptr = (const u32 *)ptr8;
u32 bits = 0;
for (u32 i = 0; i < numPixels; ++i) {
bits |= ptr[i];
}
return bits >> 24;
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include "Common/CommonTypes.h"
u8 StencilBits8888(const u8 *ptr8, u32 numPixels);
u8 StencilBits4444(const u8 *ptr8, u32 numPixels);
u8 StencilBits5551(const u8 *ptr8, u32 numPixels);
-2
View File
@@ -29,8 +29,6 @@
#include "GPU/D3D11/D3D11Util.h"
#include "GPU/Common/DepalettizeShaderCommon.h"
static const int DEPAL_TEXTURE_OLD_AGE = 120;
#ifdef _WIN32
#define SHADERLOG
#endif
-4
View File
@@ -786,10 +786,6 @@ rotateVBO:
#endif
}
bool DrawEngineD3D11::IsCodePtrVertexDecoder(const u8 *ptr) const {
return decJitCache_->IsInSpace(ptr);
}
void DrawEngineD3D11::TessellationDataTransferD3D11::SendDataToShader(const float * pos, const float * tex, const float * col, int size, bool hasColor, bool hasTexCoords) {
// Position
if (prevSize < size) {
-2
View File
@@ -136,8 +136,6 @@ public:
DecodeVerts();
}
bool IsCodePtrVertexDecoder(const u8 *ptr) const;
void DispatchFlush() override { Flush(); }
void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) override {
SubmitPrim(verts, inds, prim, vertexCount, vertType, bytesRead);
+10 -387
View File
@@ -133,22 +133,9 @@ FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw)
ShaderTranslationInit();
CompilePostShader();
D3D11_TEXTURE2D_DESC packDesc{};
packDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
packDesc.BindFlags = 0;
packDesc.Width = 512; // 512x512 is the maximum size of a framebuffer on the PSP.
packDesc.Height = 512;
packDesc.ArraySize = 1;
packDesc.MipLevels = 1;
packDesc.Usage = D3D11_USAGE_STAGING;
packDesc.SampleDesc.Count = 1;
packDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
ASSERT_SUCCESS(device_->CreateTexture2D(&packDesc, nullptr, &packTexture_));
}
FramebufferManagerD3D11::~FramebufferManagerD3D11() {
packTexture_->Release();
ShaderTranslationShutdown();
// Drawing cleanup
@@ -207,6 +194,11 @@ void FramebufferManagerD3D11::SetShaderManager(ShaderManagerD3D11 *sm) {
shaderManager_ = sm;
}
void FramebufferManagerD3D11::SetDrawEngine(DrawEngineD3D11 *td) {
drawEngineD3D11_ = td;
drawEngine_ = td;
}
void FramebufferManagerD3D11::DisableState() {
context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0xF], nullptr, 0xFFFFFFFF);
context_->RSSetState(stockD3D11.rasterStateNoCull);
@@ -283,7 +275,7 @@ void FramebufferManagerD3D11::CompilePostShader() {
}
void FramebufferManagerD3D11::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) {
u8 *convBuf = NULL;
u8 *convBuf = nullptr;
// TODO: Check / use D3DCAPS2_DYNAMICTEXTURES?
if (drawPixelsTex_ && (drawPixelsTexW_ != width || drawPixelsTexH_ != height)) {
@@ -593,60 +585,6 @@ void FramebufferManagerD3D11::BindFramebufferAsColorTexture(int stage, VirtualFr
}
}
void FramebufferManagerD3D11::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) {
if (vfb) {
// We'll pseudo-blit framebuffers here to get a resized version of vfb.
OptimizeDownloadRange(vfb, x, y, w, h);
if (vfb->renderWidth == vfb->width && vfb->renderHeight == vfb->height) {
// No need to blit
PackFramebufferD3D11_(vfb, x, y, w, h);
}
else {
VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb);
BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0);
PackFramebufferD3D11_(nvfb, x, y, w, h);
}
textureCacheD3D11_->ForgetLastTexture();
RebindFramebuffer();
}
}
void FramebufferManagerD3D11::DownloadFramebufferForClut(u32 fb_address, u32 loadBytes) {
VirtualFramebuffer *vfb = GetVFBAt(fb_address);
if (vfb && vfb->fb_stride != 0) {
const u32 bpp = vfb->drawnFormat == GE_FORMAT_8888 ? 4 : 2;
int x = 0;
int y = 0;
int pixels = loadBytes / bpp;
// The height will be 1 for each stride or part thereof.
int w = std::min(pixels % vfb->fb_stride, (int)vfb->width);
int h = std::min((pixels + vfb->fb_stride - 1) / vfb->fb_stride, (int)vfb->height);
// We might still have a pending draw to the fb in question, flush if so.
FlushBeforeCopy();
// No need to download if we already have it.
if (!vfb->memoryUpdated && vfb->clutUpdatedBytes < loadBytes) {
// We intentionally don't call OptimizeDownloadRange() here - we don't want to over download.
// CLUT framebuffers are often incorrectly estimated in size.
if (x == 0 && y == 0 && w == vfb->width && h == vfb->height) {
vfb->memoryUpdated = true;
}
vfb->clutUpdatedBytes = loadBytes;
// We'll pseudo-blit framebuffers here to get a resized version of vfb.
VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb);
BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0);
PackFramebufferD3D11_(nvfb, x, y, w, h);
textureCacheD3D11_->ForgetLastTexture();
RebindFramebuffer();
}
}
}
bool FramebufferManagerD3D11::CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
nvfb->colorDepth = Draw::FBO_8888;
@@ -762,95 +700,6 @@ void FramebufferManagerD3D11::BlitFramebuffer(VirtualFramebuffer *dst, int dstX,
false);
}
// TODO: SSE/NEON
// Could also make C fake-simd for 64-bit, two 8888 pixels fit in a register :)
void ConvertFromRGBA8888(u8 *dst, u8 *src, u32 dstStride, u32 srcStride, u32 width, u32 height, GEBufferFormat format) {
// Must skip stride in the cases below. Some games pack data into the cracks, like MotoGP.
const u32 *src32 = (const u32 *)src;
if (format == GE_FORMAT_8888) {
u32 *dst32 = (u32 *)dst;
if (src == dst) {
return;
} else {
for (u32 y = 0; y < height; ++y) {
memcpy(dst32, src32, width * 4);
src32 += srcStride;
dst32 += dstStride;
}
}
} else {
// But here it shouldn't matter if they do intersect
u16 *dst16 = (u16 *)dst;
switch (format) {
case GE_FORMAT_565: // BGR 565
for (u32 y = 0; y < height; ++y) {
ConvertRGBA8888ToRGB565(dst16, src32, width);
src32 += srcStride;
dst16 += dstStride;
}
break;
case GE_FORMAT_5551: // ABGR 1555
for (u32 y = 0; y < height; ++y) {
ConvertRGBA8888ToRGBA5551(dst16, src32, width);
src32 += srcStride;
dst16 += dstStride;
}
break;
case GE_FORMAT_4444: // ABGR 4444
for (u32 y = 0; y < height; ++y) {
ConvertRGBA8888ToRGBA4444(dst16, src32, width);
src32 += srcStride;
dst16 += dstStride;
}
break;
case GE_FORMAT_8888:
case GE_FORMAT_INVALID:
// Not possible.
break;
}
}
}
// This function takes an already correctly-sized framebuffer and packs it into RAM.
// Does not need to account for scaling.
// Color conversion is currently done on CPU but should be done on GPU.
void FramebufferManagerD3D11::PackFramebufferD3D11_(VirtualFramebuffer *vfb, int x, int y, int w, int h) {
if (!vfb->fbo) {
ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackFramebufferD3D11_: vfb->fbo == 0");
return;
}
const u32 fb_address = (0x04000000) | vfb->fb_address;
const int dstBpp = vfb->format == GE_FORMAT_8888 ? 4 : 2;
// We always need to convert from the framebuffer native format.
// Right now that's always 8888.
DEBUG_LOG(G3D, "Reading framebuffer to mem, fb_address = %08x", fb_address);
ID3D11Texture2D *colorTex = (ID3D11Texture2D *)draw_->GetFramebufferAPITexture(vfb->fbo, Draw::FB_COLOR_BIT, 0);
// TODO: Only copy the necessary rectangle.
D3D11_BOX srcBox{ (UINT)x, (UINT)y, 0, (UINT)(x+w), (UINT)(y+h), 1 };
context_->CopySubresourceRegion(packTexture_, 0, x, y, 0, colorTex, 0, &srcBox);
// Ideally, we'd round robin between two packTexture_, and simply use the other one. Though if the game
// does a once-off copy, that won't work at all.
// BIG GPU STALL
D3D11_MAPPED_SUBRESOURCE map;
HRESULT result = context_->Map(packTexture_, 0, D3D11_MAP_READ, 0, &map);
if (FAILED(result)) {
return;
}
// TODO: Handle the other formats? We don't currently create them, I think.
const int srcByteOffset = y * map.RowPitch + x * 4;
const int dstByteOffset = (y * vfb->fb_stride + x) * dstBpp;
// Pixel size always 4 here because we always request BGRA8888.
ConvertFromRGBA8888(Memory::GetPointer(fb_address + dstByteOffset), (u8 *)map.pData + srcByteOffset, vfb->fb_stride, map.RowPitch/4, w, h, vfb->format);
context_->Unmap(packTexture_, 0);
}
// Nobody calls this yet.
void FramebufferManagerD3D11::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h) {
if (!vfb->fbo) {
@@ -869,30 +718,11 @@ void FramebufferManagerD3D11::DeviceLost() {
DestroyAllFBOs();
}
std::vector<FramebufferInfo> FramebufferManagerD3D11::GetFramebufferList() {
std::vector<FramebufferInfo> list;
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *vfb = vfbs_[i];
FramebufferInfo info;
info.fb_address = vfb->fb_address;
info.z_address = vfb->z_address;
info.format = vfb->format;
info.width = vfb->width;
info.height = vfb->height;
info.fbo = vfb->fbo;
list.push_back(info);
}
return list;
}
void FramebufferManagerD3D11::DestroyAllFBOs() {
currentRenderVfb_ = 0;
displayFramebuf_ = 0;
prevDisplayFramebuf_ = 0;
prevPrevDisplayFramebuf_ = 0;
currentRenderVfb_ = nullptr;
displayFramebuf_ = nullptr;
prevDisplayFramebuf_ = nullptr;
prevPrevDisplayFramebuf_ = nullptr;
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *vfb = vfbs_[i];
@@ -915,17 +745,6 @@ void FramebufferManagerD3D11::DestroyAllFBOs() {
DisableState();
}
void FramebufferManagerD3D11::FlushBeforeCopy() {
// Flush anything not yet drawn before blitting, downloading, or uploading.
// This might be a stalled list, or unflushed before a block transfer, etc.
// TODO: It's really bad that we are calling SetRenderFramebuffer here with
// all the irrelevant state checking it'll use to decide what to do. Should
// do something more focused here.
SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
drawEngine_->Flush();
}
void FramebufferManagerD3D11::Resized() {
FramebufferManagerCommon::Resized();
@@ -936,199 +755,3 @@ void FramebufferManagerD3D11::Resized() {
// Might have a new post shader - let's compile it.
CompilePostShader();
}
// Lots of this code could be shared (like the downsampling).
bool FramebufferManagerD3D11::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) {
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {
vfb = GetVFBAt(fb_address);
}
if (!vfb) {
// If there's no vfb and we're drawing there, must be memory?
buffer = GPUDebugBuffer(Memory::GetPointer(fb_address | 0x04000000), fb_stride, 512, format);
return true;
}
int w = vfb->renderWidth, h = vfb->renderHeight;
Draw::Framebuffer *fboForRead = nullptr;
if (vfb->fbo) {
if (maxRes > 0 && vfb->renderWidth > vfb->width * maxRes) {
w = vfb->width * maxRes;
h = vfb->height * maxRes;
Draw::Framebuffer *tempFBO = GetTempFBO(w, h);
VirtualFramebuffer tempVfb = *vfb;
tempVfb.fbo = tempFBO;
tempVfb.bufferWidth = vfb->width;
tempVfb.bufferHeight = vfb->height;
tempVfb.renderWidth = w;
tempVfb.renderHeight = h;
BlitFramebuffer(&tempVfb, 0, 0, vfb, 0, 0, vfb->width, vfb->height, 0);
fboForRead = tempFBO;
} else {
fboForRead = vfb->fbo;
}
}
if (!fboForRead)
return false;
buffer.Allocate(w, h, GE_FORMAT_8888, !useBufferedRendering_, true);
ID3D11Texture2D *packTex;
D3D11_TEXTURE2D_DESC packDesc{};
packDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
packDesc.BindFlags = 0;
packDesc.Width = w;
packDesc.Height = h;
packDesc.ArraySize = 1;
packDesc.MipLevels = 1;
packDesc.Usage = D3D11_USAGE_STAGING;
packDesc.SampleDesc.Count = 1;
packDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
ASSERT_SUCCESS(device_->CreateTexture2D(&packDesc, nullptr, &packTex));
ID3D11Texture2D *nativeTex = (ID3D11Texture2D *)draw_->GetFramebufferAPITexture(fboForRead, Draw::FB_COLOR_BIT, 0);
context_->CopyResource(packTex, nativeTex);
D3D11_MAPPED_SUBRESOURCE map;
context_->Map(packTex, 0, D3D11_MAP_READ, 0, &map);
for (int y = 0; y < h; y++) {
uint8_t *dest = (uint8_t *)buffer.GetData() + y * w * 4;
const uint8_t *src = ((const uint8_t *)map.pData) + map.RowPitch * y;
memcpy(dest, src, 4 * w);
}
context_->Unmap(packTex, 0);
packTex->Release();
return true;
}
bool FramebufferManagerD3D11::GetDepthStencilBuffer(VirtualFramebuffer *vfb, GPUDebugBuffer &buffer, bool stencil) {
int w = vfb->renderWidth, h = vfb->renderHeight;
Draw::Framebuffer *fboForRead = nullptr;
fboForRead = vfb->fbo;
if (stencil) {
buffer.Allocate(w, h, GPU_DBG_FORMAT_8BIT);
} else if (gstate_c.Supports(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) {
buffer.Allocate(w, h, GPU_DBG_FORMAT_FLOAT_DIV_256);
} else {
buffer.Allocate(w, h, GPU_DBG_FORMAT_FLOAT);
}
ID3D11Texture2D *packTex;
D3D11_TEXTURE2D_DESC packDesc{};
packDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
packDesc.BindFlags = 0;
packDesc.Width = w;
packDesc.Height = h;
packDesc.ArraySize = 1;
packDesc.MipLevels = 1;
packDesc.Usage = D3D11_USAGE_STAGING;
packDesc.SampleDesc.Count = 1;
packDesc.Format = (DXGI_FORMAT)draw_->GetFramebufferAPITexture(fboForRead, Draw::FB_DEPTH_BIT | Draw::FB_FORMAT_BIT, 0);
ASSERT_SUCCESS(device_->CreateTexture2D(&packDesc, nullptr, &packTex));
ID3D11Texture2D *nativeTex = (ID3D11Texture2D *)draw_->GetFramebufferAPITexture(fboForRead, Draw::FB_DEPTH_BIT, 0);
context_->CopyResource(packTex, nativeTex);
D3D11_MAPPED_SUBRESOURCE map;
context_->Map(packTex, 0, D3D11_MAP_READ, 0, &map);
for (int y = 0; y < h; y++) {
float *dest = (float *)(buffer.GetData() + y * w * 4);
u8 *destStencil = buffer.GetData() + y * w;
const uint32_t *src = (const uint32_t *)((const uint8_t *)map.pData + map.RowPitch * y);
for (int x = 0; x < w; x++) {
if (stencil) {
destStencil[x] = src[x] >> 24;
} else {
dest[x] = (src[x] & 0xFFFFFF) / (256.f * 256.f * 256.f);
}
}
}
context_->Unmap(packTex, 0);
packTex->Release();
return true;
}
bool FramebufferManagerD3D11::GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) {
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {
vfb = GetVFBAt(fb_address);
}
if (!vfb) {
// If there's no vfb and we're drawing there, must be memory?
buffer = GPUDebugBuffer(Memory::GetPointer(z_address | 0x04000000), z_stride, 512, GPU_DBG_FORMAT_16BIT);
return true;
}
if (!vfb->fbo) {
return false;
}
return GetDepthStencilBuffer(vfb, buffer, false);
}
bool FramebufferManagerD3D11::GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) {
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {
vfb = GetVFBAt(fb_address);
}
if (!vfb) {
return false;
}
if (!vfb->fbo) {
return false;
}
return GetDepthStencilBuffer(vfb, buffer, true);
}
bool FramebufferManagerD3D11::GetOutputFramebuffer(GPUDebugBuffer &buffer) {
ID3D11Texture2D *backbuffer = (ID3D11Texture2D *)draw_->GetNativeObject(Draw::NativeObject::BACKBUFFER_COLOR_TEX);
if (!backbuffer) {
ERROR_LOG(G3D, "Failed to get backbuffer from draw context");
return false;
}
D3D11_TEXTURE2D_DESC desc;
backbuffer->GetDesc(&desc);
int w = desc.Width;
int h = desc.Height;
buffer.Allocate(w, h, GE_FORMAT_8888, !useBufferedRendering_, true);
ID3D11Texture2D *packTex;
D3D11_TEXTURE2D_DESC packDesc{};
packDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
packDesc.BindFlags = 0;
packDesc.Width = w;
packDesc.Height = h;
packDesc.ArraySize = 1;
packDesc.MipLevels = 1;
packDesc.Usage = D3D11_USAGE_STAGING;
packDesc.SampleDesc.Count = 1;
packDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
ASSERT_SUCCESS(device_->CreateTexture2D(&packDesc, nullptr, &packTex));
context_->CopyResource(packTex, backbuffer);
D3D11_MAPPED_SUBRESOURCE map;
context_->Map(packTex, 0, D3D11_MAP_READ, 0, &map);
for (int y = 0; y < h; y++) {
uint8_t *dest = (uint8_t *)buffer.GetData() + y * w * 4;
const uint8_t *src = ((const uint8_t *)map.pData) + map.RowPitch * y;
memcpy(dest, src, 4 * w);
}
context_->Unmap(packTex, 0);
packTex->Release();
return true;
}
+2 -22
View File
@@ -43,10 +43,7 @@ public:
void SetTextureCache(TextureCacheD3D11 *tc);
void SetShaderManager(ShaderManagerD3D11 *sm);
void SetDrawEngine(DrawEngineD3D11 *td) {
drawEngine_ = td;
}
void SetDrawEngine(DrawEngineD3D11 *td);
void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) override;
void DestroyAllFBOs();
@@ -60,18 +57,8 @@ public:
void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);
void ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) override;
void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes) override;
std::vector<FramebufferInfo> GetFramebufferList();
virtual bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override;
bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) override;
bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override;
bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) override;
bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override;
virtual void RebindFramebuffer() override;
// TODO: Remove
@@ -81,7 +68,6 @@ public:
protected:
void DisableState() override;
void FlushBeforeCopy() override;
// Used by ReadFramebufferToMemory and later framebuffer block copies
void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) override;
@@ -94,13 +80,11 @@ private:
void BindPostShader(const PostShaderUniforms &uniforms) override;
void Bind2DShader() override;
void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) override;
void PackFramebufferD3D11_(VirtualFramebuffer *vfb, int x, int y, int w, int h);
void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h);
void SimpleBlit(
Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2,
Draw::Framebuffer *src, float srcX1, float srcY1, float srcX2, float srcY2,
bool linearFilter);
bool GetDepthStencilBuffer(VirtualFramebuffer *vfb, GPUDebugBuffer &buffer, bool stencil);
ID3D11Device *device_;
ID3D11DeviceContext *context_;
@@ -133,11 +117,7 @@ private:
TextureCacheD3D11 *textureCacheD3D11_;
ShaderManagerD3D11 *shaderManagerD3D11_;
DrawEngineD3D11 *drawEngine_;
// Permanent 1:1 readback texture, 512x512 fixed
// For larger debug readbacks, we create/destroy textures on the fly.
ID3D11Texture2D *packTexture_;
DrawEngineD3D11 *drawEngineD3D11_;
// Used by post-processing shader
// Postprocessing
+2 -20
View File
@@ -317,12 +317,13 @@ void GPU_D3D11::EndHostFrame() {
}
void GPU_D3D11::BeginFrameInternal() {
GPUCommon::BeginFrameInternal();
textureCacheD3D11_->StartFrame();
drawEngine_.BeginFrame();
depalShaderCache_->Decimate();
// fragmentTestCache_.Decimate();
GPUCommon::BeginFrameInternal();
shaderManagerD3D11_->DirtyLastShader();
framebufferManagerD3D11_->BeginFrame();
@@ -755,10 +756,6 @@ void GPU_D3D11::ClearShaderCache() {
shaderManagerD3D11_->ClearShaders();
}
std::vector<FramebufferInfo> GPU_D3D11::GetFramebufferList() {
return framebufferManagerD3D11_->GetFramebufferList();
}
void GPU_D3D11::DoState(PointerWrap &p) {
GPUCommon::DoState(p);
@@ -774,21 +771,6 @@ void GPU_D3D11::DoState(PointerWrap &p) {
}
}
bool GPU_D3D11::GetCurrentTexture(GPUDebugBuffer &buffer, int level) {
if (!gstate.isTextureMapEnabled()) {
return false;
}
return textureCacheD3D11_->GetCurrentTextureDebug(buffer, level);
}
bool GPU_D3D11::GetCurrentClut(GPUDebugBuffer &buffer) {
return textureCacheD3D11_->GetCurrentClutBuffer(buffer);
}
bool GPU_D3D11::GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) {
return drawEngine_.GetCurrentSimpleVertices(count, vertices, indices);
}
std::vector<std::string> GPU_D3D11::DebugGetShaderIDs(DebugShaderType type) {
switch (type) {
case SHADER_TYPE_VERTEXLOADER:
-5
View File
@@ -60,11 +60,6 @@ public:
primaryInfo = reportingPrimaryInfo_;
fullInfo = reportingFullInfo_;
}
std::vector<FramebufferInfo> GetFramebufferList() override;
bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override;
bool GetCurrentClut(GPUDebugBuffer &buffer) override;
bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) override;
typedef void (GPU_D3D11::*CmdFunc)(u32 op, u32 diff);
struct CommandInfo {
+1 -33
View File
@@ -21,6 +21,7 @@
#include "ext/native/thin3d/thin3d.h"
#include "Core/Reporting.h"
#include "GPU/Common/StencilCommon.h"
#include "GPU/D3D11/FramebufferManagerD3D11.h"
#include "GPU/D3D11/FragmentShaderGeneratorD3D11.h"
#include "GPU/D3D11/ShaderManagerD3D11.h"
@@ -71,39 +72,6 @@ VS_OUT main(VS_IN In) {
}
)";
static u8 StencilBits5551(const u8 *ptr8, u32 numPixels) {
const u32 *ptr = (const u32 *)ptr8;
for (u32 i = 0; i < numPixels / 2; ++i) {
if (ptr[i] & 0x80008000) {
return 1;
}
}
return 0;
}
static u8 StencilBits4444(const u8 *ptr8, u32 numPixels) {
const u32 *ptr = (const u32 *)ptr8;
u32 bits = 0;
for (u32 i = 0; i < numPixels / 2; ++i) {
bits |= ptr[i];
}
return ((bits >> 12) & 0xF) | (bits >> 28);
}
static u8 StencilBits8888(const u8 *ptr8, u32 numPixels) {
const u32 *ptr = (const u32 *)ptr8;
u32 bits = 0;
for (u32 i = 0; i < numPixels; ++i) {
bits |= ptr[i];
}
return bits >> 24;
}
// TODO : If SV_StencilRef is available (D3D11.3) then this can be done in a single pass.
bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZero) {
if (!MayIntersectFramebuffer(addr)) {
+2 -3
View File
@@ -516,9 +516,6 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry, bool replaceIma
}
}
// If GLES3 is available, we can preallocate the storage, which makes texture loading more efficient.
DXGI_FORMAT dstFmt = GetDestFormat(GETextureFormat(entry->format), gstate.getClutPaletteFormat());
int scaleFactor = standardScaleFactor_;
// Rachet down scale factor in low-memory mode.
@@ -575,6 +572,8 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry, bool replaceIma
maxLevel = 0;
}
DXGI_FORMAT dstFmt = GetDestFormat(GETextureFormat(entry->format), gstate.getClutPaletteFormat());
if (IsFakeMipmapChange()) {
// NOTE: Since the level is not part of the cache key, we assume it never changes.
u8 level = std::max(0, gstate.getTexLevelOffset16() / 16);
-4
View File
@@ -707,10 +707,6 @@ rotateVBO:
host->GPUNotifyDraw();
}
bool DrawEngineDX9::IsCodePtrVertexDecoder(const u8 *ptr) const {
return decJitCache_->IsInSpace(ptr);
}
void DrawEngineDX9::TessellationDataTransferDX9::SendDataToShader(const float * pos, const float * tex, const float * col, int size, bool hasColor, bool hasTexCoords)
{
}
-2
View File
@@ -133,8 +133,6 @@ public:
DecodeVerts();
}
bool IsCodePtrVertexDecoder(const u8 *ptr) const;
void DispatchFlush() override { Flush(); }
void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) override {
SubmitPrim(verts, inds, prim, vertexCount, vertType, bytesRead);
+6 -80
View File
@@ -155,6 +155,11 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
shaderManager_ = sm;
}
void FramebufferManagerDX9::SetDrawEngine(DrawEngineDX9 *td) {
drawEngineD3D9_ = td;
drawEngine_ = td;
}
void FramebufferManagerDX9::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) {
u8 *convBuf = NULL;
D3DLOCKED_RECT rect;
@@ -473,55 +478,6 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
}
}
void FramebufferManagerDX9::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) {
if (vfb) {
// We'll pseudo-blit framebuffers here to get a resized version of vfb.
VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb);
OptimizeDownloadRange(vfb, x, y, w, h);
BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0);
PackFramebufferDirectx9_(nvfb, x, y, w, h);
textureCacheDX9_->ForgetLastTexture();
RebindFramebuffer();
}
}
void FramebufferManagerDX9::DownloadFramebufferForClut(u32 fb_address, u32 loadBytes) {
VirtualFramebuffer *vfb = GetVFBAt(fb_address);
if (vfb && vfb->fb_stride != 0) {
const u32 bpp = vfb->drawnFormat == GE_FORMAT_8888 ? 4 : 2;
int x = 0;
int y = 0;
int pixels = loadBytes / bpp;
// The height will be 1 for each stride or part thereof.
int w = std::min(pixels % vfb->fb_stride, (int)vfb->width);
int h = std::min((pixels + vfb->fb_stride - 1) / vfb->fb_stride, (int)vfb->height);
// We might still have a pending draw to the fb in question, flush if so.
FlushBeforeCopy();
// No need to download if we already have it.
if (!vfb->memoryUpdated && vfb->clutUpdatedBytes < loadBytes) {
// We intentionally don't call OptimizeDownloadRange() here - we don't want to over download.
// CLUT framebuffers are often incorrectly estimated in size.
if (x == 0 && y == 0 && w == vfb->width && h == vfb->height) {
vfb->memoryUpdated = true;
}
vfb->clutUpdatedBytes = loadBytes;
// We'll pseudo-blit framebuffers here to get a resized version of vfb.
VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb);
BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0);
PackFramebufferDirectx9_(nvfb, x, y, w, h);
textureCacheDX9_->ForgetLastTexture();
RebindFramebuffer();
}
}
}
bool FramebufferManagerDX9::CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
nvfb->colorDepth = Draw::FBO_8888;
@@ -640,7 +596,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
}
}
void FramebufferManagerDX9::PackFramebufferDirectx9_(VirtualFramebuffer *vfb, int x, int y, int w, int h) {
void FramebufferManagerDX9::PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h) {
if (!vfb->fbo) {
ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackFramebufferDirectx9_: vfb->fbo == 0");
return;
@@ -737,25 +693,6 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
DestroyAllFBOs();
}
std::vector<FramebufferInfo> FramebufferManagerDX9::GetFramebufferList() {
std::vector<FramebufferInfo> list;
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *vfb = vfbs_[i];
FramebufferInfo info;
info.fb_address = vfb->fb_address;
info.z_address = vfb->z_address;
info.format = vfb->format;
info.width = vfb->width;
info.height = vfb->height;
info.fbo = vfb->fbo;
list.push_back(info);
}
return list;
}
void FramebufferManagerDX9::DecimateFBOs() {
FramebufferManagerCommon::DecimateFBOs();
for (auto it = offscreenSurfaces_.begin(); it != offscreenSurfaces_.end(); ) {
@@ -800,17 +737,6 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
DisableState();
}
void FramebufferManagerDX9::FlushBeforeCopy() {
// Flush anything not yet drawn before blitting, downloading, or uploading.
// This might be a stalled list, or unflushed before a block transfer, etc.
// TODO: It's really bad that we are calling SetRenderFramebuffer here with
// all the irrelevant state checking it'll use to decide what to do. Should
// do something more focused here.
SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
drawEngine_->Flush();
}
void FramebufferManagerDX9::Resized() {
FramebufferManagerCommon::Resized();
+3 -12
View File
@@ -45,10 +45,7 @@ public:
void SetTextureCache(TextureCacheDX9 *tc);
void SetShaderManager(ShaderManagerDX9 *sm);
void SetDrawEngine(DrawEngineDX9 *td) {
drawEngine_ = td;
}
void SetDrawEngine(DrawEngineDX9 *td);
void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) override;
void DestroyAllFBOs();
@@ -62,11 +59,6 @@ public:
void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);
void ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) override;
void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes) override;
std::vector<FramebufferInfo> GetFramebufferList();
virtual bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override;
bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes);
@@ -84,7 +76,6 @@ protected:
void BindPostShader(const PostShaderUniforms &uniforms) override;
void SetViewport2D(int x, int y, int w, int h) override;
void DisableState() override;
void FlushBeforeCopy() override;
void DecimateFBOs() override;
// Used by ReadFramebufferToMemory and later framebuffer block copies
@@ -95,7 +86,7 @@ protected:
private:
void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) override;
void PackFramebufferDirectx9_(VirtualFramebuffer *vfb, int x, int y, int w, int h);
void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h) override;
void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h);
bool GetRenderTargetFramebuffer(LPDIRECT3DSURFACE9 renderTarget, LPDIRECT3DSURFACE9 offscreen, int w, int h, GPUDebugBuffer &buffer);
@@ -120,7 +111,7 @@ private:
TextureCacheDX9 *textureCacheDX9_;
ShaderManagerDX9 *shaderManagerDX9_;
DrawEngineDX9 *drawEngine_;
DrawEngineDX9 *drawEngineD3D9_;
struct TempFBO {
Draw::Framebuffer *fbo;
+1 -102
View File
@@ -295,7 +295,7 @@ void GPU_DX9::BeginFrameInternal() {
GPUCommon::BeginFrameInternal();
shaderManagerDX9_->DirtyShader();
framebufferManagerDX9_->BeginFrame();
framebufferManager_->BeginFrame();
}
void GPU_DX9::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) {
@@ -688,10 +688,6 @@ void GPU_DX9::ClearShaderCache() {
shaderManagerDX9_->ClearCache(true);
}
std::vector<FramebufferInfo> GPU_DX9::GetFramebufferList() {
return framebufferManagerDX9_->GetFramebufferList();
}
void GPU_DX9::DoState(PointerWrap &p) {
GPUCommon::DoState(p);
@@ -707,103 +703,6 @@ void GPU_DX9::DoState(PointerWrap &p) {
}
}
bool GPU_DX9::GetCurrentTexture(GPUDebugBuffer &buffer, int level) {
if (!gstate.isTextureMapEnabled()) {
return false;
}
textureCacheDX9_->SetTexture(true);
textureCacheDX9_->ApplyTexture();
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
LPDIRECT3DBASETEXTURE9 baseTex;
LPDIRECT3DTEXTURE9 tex;
LPDIRECT3DSURFACE9 offscreen = nullptr;
HRESULT hr;
bool success = false;
hr = device_->GetTexture(0, &baseTex);
if (SUCCEEDED(hr) && baseTex != NULL) {
hr = baseTex->QueryInterface(IID_IDirect3DTexture9, (void **)&tex);
if (SUCCEEDED(hr)) {
D3DSURFACE_DESC desc;
D3DLOCKED_RECT locked;
tex->GetLevelDesc(level, &desc);
RECT rect = {0, 0, (LONG)desc.Width, (LONG)desc.Height};
hr = tex->LockRect(level, &locked, &rect, D3DLOCK_READONLY);
// If it fails, this means it's a render-to-texture, so we have to get creative.
if (FAILED(hr)) {
LPDIRECT3DSURFACE9 renderTarget = nullptr;
hr = tex->GetSurfaceLevel(level, &renderTarget);
if (renderTarget && SUCCEEDED(hr)) {
hr = device_->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &offscreen, NULL);
if (SUCCEEDED(hr)) {
hr = device_->GetRenderTargetData(renderTarget, offscreen);
if (SUCCEEDED(hr)) {
hr = offscreen->LockRect(&locked, &rect, D3DLOCK_READONLY);
}
}
renderTarget->Release();
}
}
if (SUCCEEDED(hr)) {
GPUDebugBufferFormat fmt;
int pixelSize;
switch (desc.Format) {
case D3DFMT_A1R5G5B5:
fmt = gstate_c.bgraTexture ? GPU_DBG_FORMAT_5551 : GPU_DBG_FORMAT_5551_BGRA;
pixelSize = 2;
break;
case D3DFMT_A4R4G4B4:
fmt = gstate_c.bgraTexture ? GPU_DBG_FORMAT_4444 : GPU_DBG_FORMAT_4444_BGRA;
pixelSize = 2;
break;
case D3DFMT_R5G6B5:
fmt = gstate_c.bgraTexture ? GPU_DBG_FORMAT_565 : GPU_DBG_FORMAT_565_BGRA;
pixelSize = 2;
break;
case D3DFMT_A8R8G8B8:
fmt = gstate_c.bgraTexture ? GPU_DBG_FORMAT_8888 : GPU_DBG_FORMAT_8888_BGRA;
pixelSize = 4;
break;
default:
fmt = GPU_DBG_FORMAT_INVALID;
break;
}
if (fmt != GPU_DBG_FORMAT_INVALID) {
buffer.Allocate(locked.Pitch / pixelSize, desc.Height, fmt, false);
memcpy(buffer.GetData(), locked.pBits, locked.Pitch * desc.Height);
success = true;
} else {
success = false;
}
if (offscreen) {
offscreen->UnlockRect();
offscreen->Release();
} else {
tex->UnlockRect(level);
}
}
tex->Release();
}
baseTex->Release();
}
return success;
}
bool GPU_DX9::GetCurrentClut(GPUDebugBuffer &buffer) {
return textureCacheDX9_->GetCurrentClutBuffer(buffer);
}
bool GPU_DX9::GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) {
return drawEngine_.GetCurrentSimpleVertices(count, vertices, indices);
}
std::vector<std::string> GPU_DX9::DebugGetShaderIDs(DebugShaderType type) {
switch (type) {
case SHADER_TYPE_VERTEXLOADER:
-5
View File
@@ -61,11 +61,6 @@ public:
primaryInfo = reportingPrimaryInfo_;
fullInfo = reportingFullInfo_;
}
std::vector<FramebufferInfo> GetFramebufferList() override;
bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override;
bool GetCurrentClut(GPUDebugBuffer &buffer) override;
bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) override;
typedef void (GPU_DX9::*CmdFunc)(u32 op, u32 diff);
struct CommandInfo {
+1 -34
View File
@@ -22,6 +22,7 @@
#include "gfx/d3d9_state.h"
#include "ext/native/thin3d/thin3d.h"
#include "Core/Reporting.h"
#include "GPU/Common/StencilCommon.h"
#include "GPU/Directx9/FramebufferDX9.h"
#include "GPU/Directx9/PixelShaderGeneratorDX9.h"
#include "GPU/Directx9/ShaderManagerDX9.h"
@@ -63,40 +64,6 @@ static const char *stencil_vs =
" return Out;\n"
"}\n";
static u8 StencilBits5551(const u8 *ptr8, u32 numPixels) {
const u32 *ptr = (const u32 *)ptr8;
for (u32 i = 0; i < numPixels / 2; ++i) {
if (ptr[i] & 0x80008000) {
return 1;
}
}
return 0;
}
static u8 StencilBits4444(const u8 *ptr8, u32 numPixels) {
const u32 *ptr = (const u32 *)ptr8;
u32 bits = 0;
for (u32 i = 0; i < numPixels / 2; ++i) {
bits |= ptr[i];
}
return ((bits >> 12) & 0xF) | (bits >> 28);
}
static u8 StencilBits8888(const u8 *ptr8, u32 numPixels) {
const u32 *ptr = (const u32 *)ptr8;
u32 bits = 0;
for (u32 i = 0; i < numPixels; ++i) {
bits |= ptr[i];
}
return bits >> 24;
}
bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, bool skipZero) {
if (!MayIntersectFramebuffer(addr)) {
return false;
+85
View File
@@ -793,4 +793,89 @@ bool TextureCacheDX9::DecodeTexture(u8 *output, const GPUgstate &state)
return true;
}
bool TextureCacheDX9::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) {
SetTexture(true);
ApplyTexture();
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
LPDIRECT3DBASETEXTURE9 baseTex;
LPDIRECT3DTEXTURE9 tex;
LPDIRECT3DSURFACE9 offscreen = nullptr;
HRESULT hr;
bool success = false;
hr = device_->GetTexture(0, &baseTex);
if (SUCCEEDED(hr) && baseTex != NULL) {
hr = baseTex->QueryInterface(IID_IDirect3DTexture9, (void **)&tex);
if (SUCCEEDED(hr)) {
D3DSURFACE_DESC desc;
D3DLOCKED_RECT locked;
tex->GetLevelDesc(level, &desc);
RECT rect = { 0, 0, (LONG)desc.Width, (LONG)desc.Height };
hr = tex->LockRect(level, &locked, &rect, D3DLOCK_READONLY);
// If it fails, this means it's a render-to-texture, so we have to get creative.
if (FAILED(hr)) {
LPDIRECT3DSURFACE9 renderTarget = nullptr;
hr = tex->GetSurfaceLevel(level, &renderTarget);
if (renderTarget && SUCCEEDED(hr)) {
hr = device_->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &offscreen, NULL);
if (SUCCEEDED(hr)) {
hr = device_->GetRenderTargetData(renderTarget, offscreen);
if (SUCCEEDED(hr)) {
hr = offscreen->LockRect(&locked, &rect, D3DLOCK_READONLY);
}
}
renderTarget->Release();
}
}
if (SUCCEEDED(hr)) {
GPUDebugBufferFormat fmt;
int pixelSize;
switch (desc.Format) {
case D3DFMT_A1R5G5B5:
fmt = gstate_c.bgraTexture ? GPU_DBG_FORMAT_5551 : GPU_DBG_FORMAT_5551_BGRA;
pixelSize = 2;
break;
case D3DFMT_A4R4G4B4:
fmt = gstate_c.bgraTexture ? GPU_DBG_FORMAT_4444 : GPU_DBG_FORMAT_4444_BGRA;
pixelSize = 2;
break;
case D3DFMT_R5G6B5:
fmt = gstate_c.bgraTexture ? GPU_DBG_FORMAT_565 : GPU_DBG_FORMAT_565_BGRA;
pixelSize = 2;
break;
case D3DFMT_A8R8G8B8:
fmt = gstate_c.bgraTexture ? GPU_DBG_FORMAT_8888 : GPU_DBG_FORMAT_8888_BGRA;
pixelSize = 4;
break;
default:
fmt = GPU_DBG_FORMAT_INVALID;
break;
}
if (fmt != GPU_DBG_FORMAT_INVALID) {
buffer.Allocate(locked.Pitch / pixelSize, desc.Height, fmt, false);
memcpy(buffer.GetData(), locked.pBits, locked.Pitch * desc.Height);
success = true;
} else {
success = false;
}
if (offscreen) {
offscreen->UnlockRect();
offscreen->Release();
} else {
tex->UnlockRect(level);
}
}
tex->Release();
}
baseTex->Release();
}
return success;
}
};
+2
View File
@@ -57,6 +57,8 @@ public:
void SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight);
bool GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) override;
protected:
void BindTexture(TexCacheEntry *entry) override;
void Unbind() override;
+3 -2
View File
@@ -118,8 +118,6 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l
bool hasTexcoordTess = id.Bit(VS_BIT_HAS_TEXCOORD_TESS);
bool flipNormalTess = id.Bit(VS_BIT_NORM_REVERSE_TESS);
bool scaleUV = !throughmode && (uvGenMode == GE_TEXMAP_TEXTURE_COORDS || uvGenMode == GE_TEXMAP_UNKNOWN);
DoLightComputation doLight[4] = { LIGHT_OFF, LIGHT_OFF, LIGHT_OFF, LIGHT_OFF };
if (useHWTransform) {
int shadeLight0 = doShadeMapping ? ls0 : -1;
@@ -766,6 +764,9 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l
WRITE(p, " Out.v_color1 = float3(0, 0, 0);\n");
}
bool scaleUV = !throughmode && (uvGenMode == GE_TEXMAP_TEXTURE_COORDS || uvGenMode == GE_TEXMAP_UNKNOWN);
// Step 3: UV generation
if (doTexture) {
switch (uvGenMode) {
-2
View File
@@ -26,8 +26,6 @@
#include "ext/native/gfx/GLStateCache.h"
#include "GPU/Common/DepalettizeShaderCommon.h"
static const int DEPAL_TEXTURE_OLD_AGE = 120;
#ifdef _WIN32
#define SHADERLOG
#endif
+46 -308
View File
@@ -46,8 +46,6 @@
#include "GPU/GLES/DrawEngineGLES.h"
#include "GPU/GLES/ShaderManagerGLES.h"
// #define DEBUG_READ_PIXELS 1
static const char tex_fs[] =
"#if __VERSION__ >= 130\n"
"#define varying in\n"
@@ -241,6 +239,11 @@ void FramebufferManagerGLES::SetShaderManager(ShaderManagerGLES *sm) {
shaderManager_ = sm;
}
void FramebufferManagerGLES::SetDrawEngine(DrawEngineGLES *td) {
drawEngineGL_ = td;
drawEngine_ = td;
}
FramebufferManagerGLES::~FramebufferManagerGLES() {
if (drawPixelsTex_)
glDeleteTextures(1, &drawPixelsTex_);
@@ -419,8 +422,8 @@ void FramebufferManagerGLES::DrawActiveTexture(float x, float y, float w, float
glEnableVertexAttribArray(program->a_position);
glEnableVertexAttribArray(program->a_texcoord0);
if (gstate_c.Supports(GPU_SUPPORTS_VAO)) {
drawEngine_->BindBuffer(pos, sizeof(pos), texCoords, sizeof(texCoords));
drawEngine_->BindElementBuffer(indices, sizeof(indices));
drawEngineGL_->BindBuffer(pos, sizeof(pos), texCoords, sizeof(texCoords));
drawEngineGL_->BindElementBuffer(indices, sizeof(indices));
glVertexAttribPointer(program->a_position, 3, GL_FLOAT, GL_FALSE, 12, 0);
glVertexAttribPointer(program->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, (void *)sizeof(pos));
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, 0);
@@ -573,39 +576,7 @@ void FramebufferManagerGLES::DownloadFramebufferForClut(u32 fb_address, u32 load
PROFILE_THIS_SCOPE("gpu-readback");
// Flush async just in case.
PackFramebufferAsync_(nullptr);
VirtualFramebuffer *vfb = GetVFBAt(fb_address);
if (vfb && vfb->fb_stride != 0) {
const u32 bpp = vfb->drawnFormat == GE_FORMAT_8888 ? 4 : 2;
int x = 0;
int y = 0;
int pixels = loadBytes / bpp;
// The height will be 1 for each stride or part thereof.
int w = std::min(pixels % vfb->fb_stride, (int)vfb->width);
int h = std::min((pixels + vfb->fb_stride - 1) / vfb->fb_stride, (int)vfb->height);
// We might still have a pending draw to the fb in question, flush if so.
FlushBeforeCopy();
// No need to download if we already have it.
if (!vfb->memoryUpdated && vfb->clutUpdatedBytes < loadBytes) {
// We intentionally don't call OptimizeDownloadRange() here - we don't want to over download.
// CLUT framebuffers are often incorrectly estimated in size.
if (x == 0 && y == 0 && w == vfb->width && h == vfb->height) {
vfb->memoryUpdated = true;
}
vfb->clutUpdatedBytes = loadBytes;
// We'll pseudo-blit framebuffers here to get a resized version of vfb.
VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb);
BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0);
PackFramebufferSync_(nvfb, x, y, w, h);
textureCacheGL_->ForgetLastTexture();
RebindFramebuffer();
}
}
FramebufferManagerCommon::DownloadFramebufferForClut(fb_address, loadBytes);
}
bool FramebufferManagerGLES::CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
@@ -831,60 +802,6 @@ void ConvertFromRGBA8888(u8 *dst, const u8 *src, u32 dstStride, u32 srcStride, u
}
}
#ifdef DEBUG_READ_PIXELS
// TODO: Make more generic.
static void LogReadPixelsError(GLenum error) {
switch (error) {
case GL_NO_ERROR:
break;
case GL_INVALID_ENUM:
ERROR_LOG(FRAMEBUF, "glReadPixels: GL_INVALID_ENUM");
break;
case GL_INVALID_VALUE:
ERROR_LOG(FRAMEBUF, "glReadPixels: GL_INVALID_VALUE");
break;
case GL_INVALID_OPERATION:
ERROR_LOG(FRAMEBUF, "glReadPixels: GL_INVALID_OPERATION");
break;
case GL_INVALID_FRAMEBUFFER_OPERATION:
ERROR_LOG(FRAMEBUF, "glReadPixels: GL_INVALID_FRAMEBUFFER_OPERATION");
break;
case GL_OUT_OF_MEMORY:
ERROR_LOG(FRAMEBUF, "glReadPixels: GL_OUT_OF_MEMORY");
break;
#ifndef USING_GLES2
case GL_STACK_UNDERFLOW:
ERROR_LOG(FRAMEBUF, "glReadPixels: GL_STACK_UNDERFLOW");
break;
case GL_STACK_OVERFLOW:
ERROR_LOG(FRAMEBUF, "glReadPixels: GL_STACK_OVERFLOW");
break;
#endif
default:
ERROR_LOG(FRAMEBUF, "glReadPixels: %08x", error);
break;
}
}
#endif
static void SafeGLReadPixels(GLint x, GLint y, GLsizei w, GLsizei h, GLenum fmt, GLenum type, void *pixels) {
CHECK_GL_ERROR_IF_DEBUG();
if (!gl_extensions.IsGLES || (gl_extensions.GLES3 && gl_extensions.gpuVendor != GPU_VENDOR_NVIDIA)) {
// Some drivers seem to require we specify this. See #8254.
glPixelStorei(GL_PACK_ROW_LENGTH, w);
}
glReadPixels(x, y, w, h, fmt, type, pixels);
#ifdef DEBUG_READ_PIXELS
LogReadPixelsError(glGetError());
#endif
if (!gl_extensions.IsGLES || gl_extensions.GLES3) {
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
}
CHECK_GL_ERROR_IF_DEBUG();
}
void FramebufferManagerGLES::PackFramebufferAsync_(VirtualFramebuffer *vfb) {
CHECK_GL_ERROR_IF_DEBUG();
const int MAX_PBO = 2;
@@ -944,59 +861,36 @@ void FramebufferManagerGLES::PackFramebufferAsync_(VirtualFramebuffer *vfb) {
// Order packing/readback of the framebuffer
if (vfb) {
int pixelType, pixelSize, pixelFormat, align;
bool reverseOrder = gstate_c.Supports(GPU_PREFER_REVERSE_COLOR_ORDER);
Draw::DataFormat dataFmt = Draw::DataFormat::UNDEFINED;
switch (vfb->format) {
// GL_UNSIGNED_INT_8_8_8_8 returns A B G R (little-endian, tested in Nvidia card/x86 PC)
// GL_UNSIGNED_BYTE returns R G B A in consecutive bytes ("big-endian"/not treated as 32-bit value)
// We want R G B A, so we use *_REV for 16-bit formats and GL_UNSIGNED_BYTE for 32-bit
case GE_FORMAT_4444: // 16 bit RGBA
#ifdef USING_GLES2
pixelType = GL_UNSIGNED_SHORT_4_4_4_4;
#else
pixelType = (reverseOrder ? GL_UNSIGNED_SHORT_4_4_4_4_REV : GL_UNSIGNED_SHORT_4_4_4_4);
#endif
pixelFormat = GL_RGBA;
pixelSize = 2;
align = 2;
break;
case GE_FORMAT_5551: // 16 bit RGBA
#ifdef USING_GLES2
pixelType = GL_UNSIGNED_SHORT_5_5_5_1;
#else
pixelType = (reverseOrder ? GL_UNSIGNED_SHORT_1_5_5_5_REV : GL_UNSIGNED_SHORT_5_5_5_1);
#endif
pixelFormat = GL_RGBA;
pixelSize = 2;
align = 2;
break;
case GE_FORMAT_565: // 16 bit RGB
#ifdef USING_GLES2
pixelType = GL_UNSIGNED_SHORT_5_6_5;
#else
pixelType = (reverseOrder ? GL_UNSIGNED_SHORT_5_6_5_REV : GL_UNSIGNED_SHORT_5_6_5);
#endif
pixelFormat = GL_RGB;
pixelSize = 2;
align = 2;
break;
case GE_FORMAT_8888: // 32 bit RGBA
default:
pixelType = GL_UNSIGNED_BYTE;
pixelFormat = UseBGRA8888() ? GL_BGRA_EXT : GL_RGBA;
pixelSize = 4;
align = 4;
break;
case GE_FORMAT_4444: // 16 bit RGBA
dataFmt = (reverseOrder ? Draw::DataFormat::A4R4G4B4_UNORM_PACK16 : Draw::DataFormat::B4G4R4A4_UNORM_PACK16);
break;
case GE_FORMAT_5551: // 16 bit RGBA
dataFmt = (reverseOrder ? Draw::DataFormat::A1R5G5B5_UNORM_PACK16 : Draw::DataFormat::B5G5R5A1_UNORM_PACK16);
break;
case GE_FORMAT_565: // 16 bit RGB
dataFmt = (reverseOrder ? Draw::DataFormat::R5G6B5_UNORM_PACK16 : Draw::DataFormat::B5G6R5_UNORM_PACK16);
break;
case GE_FORMAT_8888: // 32 bit RGBA
dataFmt = UseBGRA8888() ? Draw::DataFormat::B8G8R8A8_UNORM : Draw::DataFormat::R8G8B8A8_UNORM;
break;
};
if (useCPU) {
dataFmt = UseBGRA8888() ? Draw::DataFormat::B8G8R8A8_UNORM : Draw::DataFormat::R8G8B8A8_UNORM;
}
int pixelSize = (int)DataFormatSizeInBytes(dataFmt);
int align = pixelSize;
// If using the CPU, we need 4 bytes per pixel always.
u32 bufSize = vfb->fb_stride * vfb->height * (useCPU ? 4 : pixelSize);
u32 bufSize = vfb->fb_stride * vfb->height * pixelSize;
u32 fb_address = (0x04000000) | vfb->fb_address;
if (vfb->fbo) {
draw_->BindFramebufferForRead(vfb->fbo);
} else {
if (!vfb->fbo) {
ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackFramebufferAsync_: vfb->fbo == 0");
return;
}
@@ -1009,15 +903,8 @@ void FramebufferManagerGLES::PackFramebufferAsync_(VirtualFramebuffer *vfb) {
pixelBufObj_[currentPBO_].maxSize = bufSize;
}
if (useCPU) {
// If converting pixel formats on the CPU we'll always request RGBA8888
glPixelStorei(GL_PACK_ALIGNMENT, 4);
SafeGLReadPixels(0, 0, vfb->fb_stride, vfb->height, UseBGRA8888() ? GL_BGRA_EXT : GL_RGBA, GL_UNSIGNED_BYTE, 0);
} else {
// Otherwise we'll directly request the format we need and let the GPU sort it out
glPixelStorei(GL_PACK_ALIGNMENT, align);
SafeGLReadPixels(0, 0, vfb->fb_stride, vfb->height, pixelFormat, pixelType, 0);
}
// TODO: This is a hack since PBOs have not been implemented in Thin3D yet(and maybe shouldn't? maybe should do this internally?)
draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_COLOR_BIT, 0, 0, vfb->fb_stride, vfb->height, dataFmt, nullptr, vfb->fb_stride);
unbind = true;
@@ -1038,9 +925,7 @@ void FramebufferManagerGLES::PackFramebufferAsync_(VirtualFramebuffer *vfb) {
}
void FramebufferManagerGLES::PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h) {
if (vfb->fbo) {
draw_->BindFramebufferForRead(vfb->fbo);
} else {
if (!vfb->fbo) {
ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackFramebufferSync_: vfb->fbo == 0");
return;
}
@@ -1061,9 +946,9 @@ void FramebufferManagerGLES::PackFramebufferSync_(VirtualFramebuffer *vfb, int x
int dstByteOffset = y * vfb->fb_stride * dstBpp;
u8 *dst = Memory::GetPointer(fb_address + dstByteOffset);
GLubyte *packed = nullptr;
u8 *packed = nullptr;
if (!convert) {
packed = (GLubyte *)dst;
packed = (u8 *)dst;
} else {
// End result may be 16-bit but we are reading 32-bit, so there may not be enough space at fb_address
if (!convBuf_ || convBufSize_ < bufSize) {
@@ -1077,20 +962,15 @@ void FramebufferManagerGLES::PackFramebufferSync_(VirtualFramebuffer *vfb, int x
if (packed) {
DEBUG_LOG(FRAMEBUF, "Reading framebuffer to mem, bufSize = %u, fb_address = %08x", bufSize, fb_address);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
GLenum glfmt = GL_RGBA;
if (UseBGRA8888()) {
glfmt = GL_BGRA_EXT;
}
CHECK_GL_ERROR_IF_DEBUG();
SafeGLReadPixels(0, y, h == 1 ? packWidth : vfb->fb_stride, h, glfmt, GL_UNSIGNED_BYTE, packed);
int packW = h == 1 ? packWidth : vfb->fb_stride; // TODO: What's this about?
draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_COLOR_BIT, 0, y, packW, h, UseBGRA8888() ? Draw::DataFormat::B8G8R8A8_UNORM : Draw::DataFormat::R8G8B8A8_UNORM, packed, packW);
if (convert) {
ConvertFromRGBA8888(dst, packed, vfb->fb_stride, vfb->fb_stride, packWidth, h, vfb->format);
}
}
// TODO: Move this into Thin3d.
if (gl_extensions.GLES3 && glInvalidateFramebuffer != nullptr) {
#ifdef USING_GLES2
// GLES3 doesn't support using GL_READ_FRAMEBUFFER here.
@@ -1106,9 +986,7 @@ void FramebufferManagerGLES::PackFramebufferSync_(VirtualFramebuffer *vfb, int x
}
void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h) {
if (vfb->fbo) {
draw_->BindFramebufferForRead(vfb->fbo);
} else {
if (!vfb->fbo) {
ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackDepthbuffer: vfb->fbo == 0");
return;
}
@@ -1126,8 +1004,8 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int
DEBUG_LOG(FRAMEBUF, "Reading depthbuffer to mem at %08x for vfb=%08x", z_address, vfb->fb_address);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
SafeGLReadPixels(0, y, h == 1 ? packWidth : vfb->z_stride, h, GL_DEPTH_COMPONENT, GL_FLOAT, convBuf_);
int packW = h == 1 ? packWidth : vfb->z_stride;
draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, y, packW, h, Draw::DataFormat::D32F, convBuf_, packW);
int dstByteOffset = y * vfb->fb_stride * sizeof(u16);
u16 *depth = (u16 *)Memory::GetPointer(z_address + dstByteOffset);
@@ -1176,25 +1054,6 @@ void FramebufferManagerGLES::DeviceLost() {
DestroyDraw2DProgram();
}
std::vector<FramebufferInfo> FramebufferManagerGLES::GetFramebufferList() {
std::vector<FramebufferInfo> list;
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *vfb = vfbs_[i];
FramebufferInfo info;
info.fb_address = vfb->fb_address;
info.z_address = vfb->z_address;
info.format = vfb->format;
info.width = vfb->width;
info.height = vfb->height;
info.fbo = vfb->fbo;
list.push_back(info);
}
return list;
}
void FramebufferManagerGLES::DestroyAllFBOs() {
CHECK_GL_ERROR_IF_DEBUG();
currentRenderVfb_ = 0;
@@ -1224,18 +1083,6 @@ void FramebufferManagerGLES::DestroyAllFBOs() {
CHECK_GL_ERROR_IF_DEBUG();
}
void FramebufferManagerGLES::FlushBeforeCopy() {
// Flush anything not yet drawn before blitting, downloading, or uploading.
// This might be a stalled list, or unflushed before a block transfer, etc.
// TODO: It's really bad that we are calling SetRenderFramebuffer here with
// all the irrelevant state checking it'll use to decide what to do. Should
// do something more focused here.
SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
drawEngine_->Flush();
CHECK_GL_ERROR_IF_DEBUG();
}
void FramebufferManagerGLES::Resized() {
FramebufferManagerCommon::Resized();
@@ -1251,119 +1098,10 @@ void FramebufferManagerGLES::Resized() {
}
}
bool FramebufferManagerGLES::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) {
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {
vfb = GetVFBAt(fb_address);
}
if (!vfb) {
// If there's no vfb and we're drawing there, must be memory?
buffer = GPUDebugBuffer(Memory::GetPointer(fb_address | 0x04000000), fb_stride, 512, format);
return true;
}
int w = vfb->renderWidth, h = vfb->renderHeight;
if (vfb->fbo) {
if (maxRes > 0 && vfb->renderWidth > vfb->width * maxRes) {
w = vfb->width * maxRes;
h = vfb->height * maxRes;
Draw::Framebuffer *tempFBO = GetTempFBO(w, h);
VirtualFramebuffer tempVfb = *vfb;
tempVfb.fbo = tempFBO;
tempVfb.bufferWidth = vfb->width;
tempVfb.bufferHeight = vfb->height;
tempVfb.renderWidth = w;
tempVfb.renderHeight = h;
BlitFramebuffer(&tempVfb, 0, 0, vfb, 0, 0, vfb->width, vfb->height, 0);
draw_->BindFramebufferForRead(tempFBO);
} else {
draw_->BindFramebufferForRead(vfb->fbo);
}
}
buffer.Allocate(w, h, GE_FORMAT_8888, !useBufferedRendering_, true);
if (gl_extensions.GLES3 || !gl_extensions.IsGLES)
glReadBuffer(GL_COLOR_ATTACHMENT0);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
SafeGLReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer.GetData());
// We may have blitted to a temp FBO.
RebindFramebuffer();
CHECK_GL_ERROR_IF_DEBUG();
return true;
}
bool FramebufferManagerGLES::GetOutputFramebuffer(GPUDebugBuffer &buffer) {
int pw = PSP_CoreParameter().pixelWidth;
int ph = PSP_CoreParameter().pixelHeight;
// The backbuffer is flipped.
buffer.Allocate(pw, ph, GPU_DBG_FORMAT_888_RGB, true);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
SafeGLReadPixels(0, 0, pw, ph, GL_RGB, GL_UNSIGNED_BYTE, buffer.GetData());
CHECK_GL_ERROR_IF_DEBUG();
int w, h;
draw_->GetFramebufferDimensions(nullptr, &w, &h);
buffer.Allocate(w, h, GPU_DBG_FORMAT_888_RGB, true);
draw_->CopyFramebufferToMemorySync(nullptr, Draw::FB_COLOR_BIT, 0, 0, w, h, Draw::DataFormat::R8G8B8_UNORM, buffer.GetData(), w);
return true;
}
bool FramebufferManagerGLES::GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) {
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {
vfb = GetVFBAt(fb_address);
}
if (!vfb) {
// If there's no vfb and we're drawing there, must be memory?
buffer = GPUDebugBuffer(Memory::GetPointer(z_address | 0x04000000), z_stride, 512, GPU_DBG_FORMAT_16BIT);
return true;
}
if (!vfb->fbo) {
return false;
}
if (gstate_c.Supports(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) {
buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GPU_DBG_FORMAT_FLOAT_DIV_256, !useBufferedRendering_);
} else {
buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GPU_DBG_FORMAT_FLOAT, !useBufferedRendering_);
}
if (vfb->fbo)
draw_->BindFramebufferForRead(vfb->fbo);
if (gl_extensions.GLES3 || !gl_extensions.IsGLES)
glReadBuffer(GL_COLOR_ATTACHMENT0);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
SafeGLReadPixels(0, 0, vfb->renderWidth, vfb->renderHeight, GL_DEPTH_COMPONENT, GL_FLOAT, buffer.GetData());
CHECK_GL_ERROR_IF_DEBUG();
return true;
}
bool FramebufferManagerGLES::GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) {
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {
vfb = GetVFBAt(fb_address);
}
if (!vfb) {
// If there's no vfb and we're drawing there, must be memory?
// TODO: Actually get the stencil.
buffer = GPUDebugBuffer(Memory::GetPointer(fb_address | 0x04000000), fb_stride, 512, GPU_DBG_FORMAT_8888);
return true;
}
#ifndef USING_GLES2
buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GPU_DBG_FORMAT_8BIT, !useBufferedRendering_);
if (vfb->fbo)
draw_->BindFramebufferForRead(vfb->fbo);
if (gl_extensions.GLES3 || !gl_extensions.IsGLES)
glReadBuffer(GL_COLOR_ATTACHMENT0);
glPixelStorei(GL_PACK_ALIGNMENT, 2);
SafeGLReadPixels(0, 0, vfb->renderWidth, vfb->renderHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buffer.GetData());
CHECK_GL_ERROR_IF_DEBUG();
return true;
#else
return false;
#endif
}
+3 -11
View File
@@ -55,9 +55,7 @@ public:
void SetTextureCache(TextureCacheGLES *tc);
void SetShaderManager(ShaderManagerGLES *sm);
void SetDrawEngine(DrawEngineGLES *td) {
drawEngine_ = td;
}
void SetDrawEngine(DrawEngineGLES *td);
// x,y,w,h are relative to destW, destH which fill out the target completely.
void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) override;
@@ -80,13 +78,8 @@ public:
void ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) override;
void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes) override;
std::vector<FramebufferInfo> GetFramebufferList();
bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override;
bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) override;
bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override;
bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) override;
bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override;
virtual void RebindFramebuffer() override;
@@ -94,7 +87,6 @@ public:
protected:
void SetViewport2D(int x, int y, int w, int h) override;
void DisableState() override;
void FlushBeforeCopy() override;
// Used by ReadFramebufferToMemory and later framebuffer block copies
void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) override;
@@ -111,7 +103,7 @@ private:
void CompilePostShader();
void PackFramebufferAsync_(VirtualFramebuffer *vfb); // Not used under ES currently
void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h);
void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h) override;
void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h);
// Used by DrawPixels
@@ -134,7 +126,7 @@ private:
TextureCacheGLES *textureCacheGL_;
ShaderManagerGLES *shaderManagerGL_;
DrawEngineGLES *drawEngine_;
DrawEngineGLES *drawEngineGL_;
// Not used under ES currently.
AsyncPBO *pixelBufObj_; //this isn't that large
-57
View File
@@ -929,10 +929,6 @@ void GPU_GLES::CleanupBeforeUI() {
glstate.elementArrayBuffer.bind(0);
}
std::vector<FramebufferInfo> GPU_GLES::GetFramebufferList() {
return framebufferManagerGL_->GetFramebufferList();
}
void GPU_GLES::DoState(PointerWrap &p) {
GPUCommon::DoState(p);
@@ -950,59 +946,6 @@ void GPU_GLES::DoState(PointerWrap &p) {
}
}
bool GPU_GLES::GetCurrentTexture(GPUDebugBuffer &buffer, int level) {
if (!gstate.isTextureMapEnabled()) {
return false;
}
#ifndef USING_GLES2
GPUgstate saved;
if (level != 0) {
saved = gstate;
// The way we set textures is a bit complex. Let's just override level 0.
gstate.texsize[0] = gstate.texsize[level];
gstate.texaddr[0] = gstate.texaddr[level];
gstate.texbufwidth[0] = gstate.texbufwidth[level];
}
textureCacheGL_->SetTexture(true);
textureCacheGL_->ApplyTexture();
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
if (level != 0) {
gstate = saved;
}
buffer.Allocate(w, h, GE_FORMAT_8888, false);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.GetData());
return true;
#else
return false;
#endif
}
bool GPU_GLES::GetCurrentClut(GPUDebugBuffer &buffer) {
return textureCacheGL_->GetCurrentClutBuffer(buffer);
}
bool GPU_GLES::GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) {
return drawEngine_.GetCurrentSimpleVertices(count, vertices, indices);
}
bool GPU_GLES::DescribeCodePtr(const u8 *ptr, std::string &name) {
if (drawEngine_.IsCodePtrVertexDecoder(ptr)) {
name = "VertexDecoderJit";
return true;
}
return false;
}
std::vector<std::string> GPU_GLES::DebugGetShaderIDs(DebugShaderType type) {
switch (type) {
case SHADER_TYPE_VERTEXLOADER:
-7
View File
@@ -63,13 +63,6 @@ public:
primaryInfo = reportingPrimaryInfo_;
fullInfo = reportingFullInfo_;
}
std::vector<FramebufferInfo> GetFramebufferList() override;
bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override;
bool GetCurrentClut(GPUDebugBuffer &buffer) override;
bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) override;
bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
typedef void (GPU_GLES::*CmdFunc)(u32 op, u32 diff);
struct CommandInfo {
+1 -34
View File
@@ -18,6 +18,7 @@
#include "gfx_es2/glsl_program.h"
#include "Core/Reporting.h"
#include "ext/native/gfx/GLStateCache.h"
#include "GPU/Common/StencilCommon.h"
#include "GPU/GLES/FramebufferManagerGLES.h"
#include "GPU/GLES/ShaderManagerGLES.h"
#include "GPU/GLES/TextureCacheGLES.h"
@@ -59,40 +60,6 @@ static const char *stencil_vs =
" gl_Position = a_position;\n"
"}\n";
static u8 StencilBits5551(const u8 *ptr8, u32 numPixels) {
const u32 *ptr = (const u32 *)ptr8;
for (u32 i = 0; i < numPixels / 2; ++i) {
if (ptr[i] & 0x80008000) {
return 1;
}
}
return 0;
}
static u8 StencilBits4444(const u8 *ptr8, u32 numPixels) {
const u32 *ptr = (const u32 *)ptr8;
u32 bits = 0;
for (u32 i = 0; i < numPixels / 2; ++i) {
bits |= ptr[i];
}
return ((bits >> 12) & 0xF) | (bits >> 28);
}
static u8 StencilBits8888(const u8 *ptr8, u32 numPixels) {
const u32 *ptr = (const u32 *)ptr8;
u32 bits = 0;
for (u32 i = 0; i < numPixels; ++i) {
bits |= ptr[i];
}
return bits >> 24;
}
bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZero) {
if (!MayIntersectFramebuffer(addr)) {
return false;
+33
View File
@@ -1045,3 +1045,36 @@ bool TextureCacheGLES::DecodeTexture(u8* output, const GPUgstate &state) {
gstate = oldState;
return true;
}
bool TextureCacheGLES::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) {
#ifndef USING_GLES2
GPUgstate saved;
if (level != 0) {
saved = gstate;
// The way we set textures is a bit complex. Let's just override level 0.
gstate.texsize[0] = gstate.texsize[level];
gstate.texaddr[0] = gstate.texaddr[level];
gstate.texbufwidth[0] = gstate.texbufwidth[level];
}
SetTexture(true);
ApplyTexture();
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
if (level != 0) {
gstate = saved;
}
buffer.Allocate(w, h, GE_FORMAT_8888, false);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.GetData());
return true;
#else
return false;
#endif
}
+1
View File
@@ -75,6 +75,7 @@ public:
bool DecodeTexture(u8 *output, const GPUgstate &state);
void SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight);
bool GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) override;
protected:
void BindTexture(TexCacheEntry *entry) override;
+4
View File
@@ -196,6 +196,7 @@
<ClInclude Include="Common\ShaderUniforms.h" />
<ClInclude Include="Common\SoftwareTransformCommon.h" />
<ClInclude Include="Common\SplineCommon.h" />
<ClInclude Include="Common\StencilCommon.h" />
<ClInclude Include="Common\TextureDecoderNEON.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -282,6 +283,7 @@
<ClCompile Include="Common\ShaderTranslation.cpp" />
<ClCompile Include="Common\ShaderUniforms.cpp" />
<ClCompile Include="Common\SplineCommon.cpp" />
<ClCompile Include="Common\StencilCommon.cpp" />
<ClCompile Include="Common\TextureDecoderNEON.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -358,6 +360,7 @@
<ClCompile Include="Software\SoftGpu.cpp" />
<ClCompile Include="Software\TransformUnit.cpp" />
<ClCompile Include="Common\TextureDecoder.cpp" />
<ClCompile Include="Source.cpp" />
<ClCompile Include="Vulkan\DepalettizeShaderVulkan.cpp" />
<ClCompile Include="Vulkan\DrawEngineVulkan.cpp" />
<ClCompile Include="Vulkan\FragmentShaderGeneratorVulkan.cpp" />
@@ -366,6 +369,7 @@
<ClCompile Include="Vulkan\PipelineManagerVulkan.cpp" />
<ClCompile Include="Vulkan\ShaderManagerVulkan.cpp" />
<ClCompile Include="Vulkan\StateMappingVulkan.cpp" />
<ClCompile Include="Vulkan\StencilBufferVulkan.cpp" />
<ClCompile Include="Vulkan\TextureCacheVulkan.cpp" />
<ClCompile Include="Vulkan\TextureScalerVulkan.cpp" />
<ClCompile Include="Vulkan\VertexShaderGeneratorVulkan.cpp" />
+12
View File
@@ -265,6 +265,9 @@
<ClInclude Include="Debugger\Record.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="Common\StencilCommon.h">
<Filter>Common</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Math3D.cpp">
@@ -525,5 +528,14 @@
<ClCompile Include="Debugger\Record.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="Vulkan\StencilBufferVulkan.cpp">
<Filter>Vulkan</Filter>
</ClCompile>
<ClCompile Include="Source.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\StencilCommon.cpp">
<Filter>Common</Filter>
</ClCompile>
</ItemGroup>
</Project>
+23
View File
@@ -2509,6 +2509,29 @@ bool GPUCommon::GetOutputFramebuffer(GPUDebugBuffer &buffer) {
return framebufferManager_ ? framebufferManager_->GetOutputFramebuffer(buffer) : false;
}
std::vector<FramebufferInfo> GPUCommon::GetFramebufferList() {
return framebufferManager_->GetFramebufferList();
}
bool GPUCommon::GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) {
return drawEngineCommon_->GetCurrentSimpleVertices(count, vertices, indices);
}
bool GPUCommon::GetCurrentClut(GPUDebugBuffer &buffer) {
return textureCache_->GetCurrentClutBuffer(buffer);
}
bool GPUCommon::GetCurrentTexture(GPUDebugBuffer &buffer, int level) {
if (!gstate.isTextureMapEnabled()) {
return false;
}
return textureCache_->GetCurrentTextureDebug(buffer, level);
}
bool GPUCommon::DescribeCodePtr(const u8 *ptr, std::string &name) {
if (drawEngineCommon_->IsCodePtrVertexDecoder(ptr)) {
name = "VertexDecoderJit";
return true;
}
return false;
}
+9 -12
View File
@@ -169,18 +169,22 @@ public:
#define new DBG_NEW
#endif
bool DescribeCodePtr(const u8 *ptr, std::string &name) override {
return false;
}
// From GPUDebugInterface.
bool GetCurrentDisplayList(DisplayList &list) override;
bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) override;
bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override;
bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override;
bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override;
bool GetCurrentClut(GPUDebugBuffer &buffer) override;
bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) override;
bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override;
std::vector<std::string> DebugGetShaderIDs(DebugShaderType shader) override { return std::vector<std::string>(); };
std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override {
return "N/A";
}
bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
std::vector<DisplayList> ActiveDisplayLists() override;
void ResetListPC(int listID, u32 pc) override;
void ResetListStall(int listID, u32 stall) override;
@@ -223,9 +227,7 @@ public:
bool DecodeTexture(u8* dest, const GPUgstate &state) override {
return false;
}
std::vector<FramebufferInfo> GetFramebufferList() override {
return std::vector<FramebufferInfo>();
}
std::vector<FramebufferInfo> GetFramebufferList() override;
void ClearShaderCache() override {}
void CleanupBeforeUI() override {}
@@ -236,11 +238,6 @@ public:
return -1;
}
std::vector<std::string> DebugGetShaderIDs(DebugShaderType shader) override { return std::vector<std::string>(); };
std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override {
return "N/A";
}
typedef void (GPUCommon::*CmdFunc)(u32 op, u32 diff);
protected:
+6 -7
View File
@@ -146,13 +146,6 @@ void SoftGPU::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat for
void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
if (!draw_)
return;
float dstwidth = (float)PSP_CoreParameter().pixelWidth;
float dstheight = (float)PSP_CoreParameter().pixelHeight;
Draw::Viewport viewport = {0.0f, 0.0f, dstwidth, dstheight, 0.0f, 1.0f};
draw_->SetViewports(1, &viewport);
draw_->SetScissorRect(0, 0, dstwidth, dstheight);
float u0 = 0.0f;
float u1;
@@ -216,6 +209,9 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
fbTex = draw_->CreateTexture(desc);
float dstwidth = (float)PSP_CoreParameter().pixelWidth;
float dstheight = (float)PSP_CoreParameter().pixelHeight;
float x, y, w, h;
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, dstwidth, dstheight, ROTATION_LOCKED_HORIZONTAL);
@@ -242,6 +238,9 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
std::swap(v0, v1);
}
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE });
Draw::Viewport viewport = { 0.0f, 0.0f, dstwidth, dstheight, 0.0f, 1.0f };
draw_->SetViewports(1, &viewport);
draw_->SetScissorRect(0, 0, dstwidth, dstheight);
Draw::SamplerState *sampler;
if (g_Config.iBufFilter == SCALE_NEAREST) {
View File
Whitespace-only changes.
+134 -14
View File
@@ -15,33 +15,153 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Common/Vulkan/VulkanContext.h"
#include "GPU/GPUState.h"
#include "GPU/Common/DepalettizeShaderCommon.h"
#include "GPU/Vulkan/DepalettizeShaderVulkan.h"
#include "GPU/Vulkan/VulkanUtil.h"
#include "Common/Vulkan/VulkanImage.h"
DepalShaderCacheVulkan::DepalShaderCacheVulkan() {
static const char depal_vs[] = R"(#version 400
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (location = 0) in vec3 a_position;
layout (location = 1) in vec2 a_texcoord0;
layout (location = 0) out vec2 v_texcoord0;
out gl_PerVertex { vec4 gl_Position; };
void main() {
v_texcoord0 = a_texcoord0;
gl_Position = vec4(a_position, 1.0);
}
)";
static const VkComponentMapping VULKAN_4444_SWIZZLE = { VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B };
static const VkComponentMapping VULKAN_1555_SWIZZLE = { VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_A };
static const VkComponentMapping VULKAN_565_SWIZZLE = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
static const VkComponentMapping VULKAN_8888_SWIZZLE = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
static VkFormat GetClutDestFormat(GEPaletteFormat format, VkComponentMapping *componentMapping) {
switch (format) {
case GE_CMODE_16BIT_ABGR4444:
*componentMapping = VULKAN_4444_SWIZZLE;
return VK_FORMAT_B4G4R4A4_UNORM_PACK16;
case GE_CMODE_16BIT_ABGR5551:
*componentMapping = VULKAN_1555_SWIZZLE;
return VK_FORMAT_A1R5G5B5_UNORM_PACK16;
case GE_CMODE_16BIT_BGR5650:
*componentMapping = VULKAN_565_SWIZZLE;
return VK_FORMAT_B5G6R5_UNORM_PACK16;
case GE_CMODE_32BIT_ABGR8888:
*componentMapping = VULKAN_8888_SWIZZLE;
return VK_FORMAT_R8G8B8A8_UNORM;
}
return VK_FORMAT_UNDEFINED;
}
DepalShaderCacheVulkan::DepalShaderCacheVulkan(Draw::DrawContext *draw, VulkanContext *vulkan)
: draw_(draw), vulkan_(vulkan) {
std::string errors;
vshader_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_VERTEX_BIT, depal_vs, &errors);
assert(vshader_ != VK_NULL_HANDLE);
}
DepalShaderCacheVulkan::~DepalShaderCacheVulkan() {
Clear();
vulkan_->Delete().QueueDeleteShaderModule(vshader_);
}
DepalShaderVulkan *DepalShaderCacheVulkan::GetDepalettizeShader(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat) {
return nullptr;
DepalShaderVulkan *DepalShaderCacheVulkan::GetDepalettizeShader(uint32_t clutMode, GEBufferFormat pixelFormat) {
u32 id = GenerateShaderID(clutMode, pixelFormat);
auto shader = cache_.find(id);
if (shader != cache_.end()) {
return shader->second;
}
VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::FRAMEBUFFER_RENDERPASS);
char *buffer = new char[2048];
GenerateDepalShader(buffer, pixelFormat, GLSL_VULKAN);
std::string error;
VkShaderModule fshader = CompileShaderModule(vulkan_, VK_SHADER_STAGE_FRAGMENT_BIT, buffer, &error);
if (fshader == VK_NULL_HANDLE) {
Crash();
delete[] buffer;
return nullptr;
}
VkPipeline pipeline = vulkan2D_->GetPipeline(rp, vshader_, fshader);
// Can delete the shader module now that the pipeline has been created.
// Maybe don't even need to queue it..
vulkan_->Delete().QueueDeleteShaderModule(fshader);
DepalShaderVulkan *depal = new DepalShaderVulkan();
depal->pipeline = pipeline;
depal->code = buffer;
cache_[id] = depal;
return depal;
}
VulkanTexture *DepalShaderCacheVulkan::GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, u32 *rawClut) {
return nullptr;
VulkanTexture *DepalShaderCacheVulkan::GetClutTexture(GEPaletteFormat clutFormat, u32 clutID, u32 *rawClut) {
VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
const u32 realClutID = clutID ^ clutFormat;
auto oldtex = texCache_.find(realClutID);
if (oldtex != texCache_.end()) {
oldtex->second->lastFrame = gpuStats.numFlips;
return oldtex->second->texture;
}
VkComponentMapping componentMapping;
VkFormat destFormat = GetClutDestFormat(clutFormat, &componentMapping);
int texturePixels = clutFormat == GE_CMODE_32BIT_ABGR8888 ? 256 : 512;
VkBuffer pushBuffer;
uint32_t pushOffset = push_->PushAligned(rawClut, 1024, 4, &pushBuffer);
VulkanTexture *vktex = new VulkanTexture(vulkan_, alloc_);
if (!vktex->CreateDirect(cmd, texturePixels, 1, 1, destFormat,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, &componentMapping)) {
Crash();
}
vktex->UploadMip(cmd, 0, texturePixels, 1, pushBuffer, pushOffset, texturePixels);
vktex->EndCreate(cmd);
DepalTextureVulkan *tex = new DepalTextureVulkan();
tex->texture = vktex;
tex->lastFrame = gpuStats.numFlips;
texCache_[realClutID] = tex;
return tex->texture;
}
void DepalShaderCacheVulkan::Clear() {}
void DepalShaderCacheVulkan::Clear() {
for (auto shader = cache_.begin(); shader != cache_.end(); ++shader) {
// Don't need to destroy the pipelines, they're handled by Vulkan2D.
delete shader->second;
}
cache_.clear();
void DepalShaderCacheVulkan::Decimate() {}
u32 DepalShaderCacheVulkan::GenerateShaderID(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat) {
return 0;
for (auto tex = texCache_.begin(); tex != texCache_.end(); ++tex) {
delete tex->second->texture;
delete tex->second;
}
texCache_.clear();
}
bool DepalShaderCacheVulkan::CreateVertexShader() {
return false;
void DepalShaderCacheVulkan::Decimate() {
// We don't bother decimating the generated shaders, there are never very many of them.
for (auto tex = texCache_.begin(); tex != texCache_.end(); ) {
if (tex->second->lastFrame + DEPAL_TEXTURE_OLD_AGE < gpuStats.numFlips) {
delete tex->second->texture;
delete tex->second;
texCache_.erase(tex++);
} else {
++tex;
}
}
}
u32 DepalShaderCacheVulkan::GenerateShaderID(uint32_t clutMode, GEBufferFormat pixelFormat) {
return (clutMode & 0xFFFFFF) | (pixelFormat << 24);
}
+27 -11
View File
@@ -20,42 +20,58 @@
#include <map>
#include "Common/CommonTypes.h"
#include "Common/Vulkan/VulkanContext.h"
#include "Common/Vulkan/VulkanImage.h"
#include "Common/Vulkan/VulkanMemory.h"
#include "GPU/ge_constants.h"
#include "thin3d/thin3d.h"
class DepalShaderVulkan {
public:
/*
GLuint program;
GLuint fragShader;
GLint a_position;
GLint a_texcoord0;
*/
~DepalShaderVulkan() {
delete[] code;
}
// A Vulkan2D pipeline. Set texture to slot 0 and palette texture to slot 1.
VkPipeline pipeline = VK_NULL_HANDLE;
const char *code = nullptr;;
};
class DepalTextureVulkan {
public:
int texture;
VulkanTexture *texture = nullptr;
int lastFrame;
};
class VulkanTexture;
class Vulkan2D;
// Caches both shaders and palette textures.
// Could even avoid bothering with palette texture and just use uniform data...
class DepalShaderCacheVulkan {
public:
DepalShaderCacheVulkan();
DepalShaderCacheVulkan(Draw::DrawContext *draw, VulkanContext *vulkan);
~DepalShaderCacheVulkan();
// This also uploads the palette and binds the correct texture.
DepalShaderVulkan *GetDepalettizeShader(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat);
DepalShaderVulkan *GetDepalettizeShader(uint32_t clutMode, GEBufferFormat pixelFormat);
VulkanTexture *GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, u32 *rawClut);
void Clear();
void Decimate();
void SetVulkan2D(Vulkan2D *vk2d) { vulkan2D_ = vk2d; }
void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; }
void SetAllocator(VulkanDeviceAllocator *alloc) { alloc_ = alloc; }
void SetVShader(VkShaderModule vshader) { vshader_ = vshader; }
private:
u32 GenerateShaderID(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat);
bool CreateVertexShader();
u32 GenerateShaderID(uint32_t clutMode, GEBufferFormat pixelFormat);
Draw::DrawContext *draw_ = nullptr;
VulkanContext *vulkan_ = nullptr;
VulkanPushBuffer *push_ = nullptr;
VulkanDeviceAllocator *alloc_ = nullptr;
VkShaderModule vshader_ = VK_NULL_HANDLE;
Vulkan2D *vulkan2D_ = nullptr;
// GLuint vertexShader_;
std::map<u32, DepalShaderVulkan *> cache_;
+77 -73
View File
@@ -21,6 +21,7 @@
#include "base/timeutil.h"
#include "math/dataconv.h"
#include "profiler/profiler.h"
#include "thin3d/VulkanRenderManager.h"
#include "Common/MemoryUtil.h"
#include "Core/MemMap.h"
@@ -56,7 +57,7 @@ enum {
};
#define VERTEXCACHE_DECIMATION_INTERVAL 17
#define DESCRIPTORSET_DECIMATION_INTERVAL 13
#define DESCRIPTORSET_DECIMATION_INTERVAL 1 // Temporarily cut to 1. Handle reuse breaks this when textures get deleted.
enum { VAI_KILL_AGE = 120, VAI_UNRELIABLE_KILL_AGE = 240, VAI_UNRELIABLE_KILL_MAX = 4 };
@@ -78,7 +79,6 @@ enum {
DrawEngineVulkan::DrawEngineVulkan(VulkanContext *vulkan, Draw::DrawContext *draw)
: vulkan_(vulkan),
draw_(draw),
curFrame_(0),
stats_{},
vai_(1024) {
decOptions_.expandAllWeightsToFloat = false;
@@ -94,7 +94,7 @@ DrawEngineVulkan::DrawEngineVulkan(VulkanContext *vulkan, Draw::DrawContext *dra
InitDeviceObjects();
tessDataTransfer = new TessellationDataTransferVulkan(vulkan);
tessDataTransfer = new TessellationDataTransferVulkan(vulkan, draw);
}
void DrawEngineVulkan::InitDeviceObjects() {
@@ -125,7 +125,8 @@ void DrawEngineVulkan::InitDeviceObjects() {
bindings[4].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
bindings[4].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
bindings[4].binding = DRAW_BINDING_DYNUBO_BONE;
// Hardware tessellation
// Hardware tessellation. TODO: Don't allocate these unless actually drawing splines.
// Will require additional
bindings[5].descriptorCount = 1;
bindings[5].pImmutableSamplers = nullptr;
bindings[5].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
@@ -151,9 +152,9 @@ void DrawEngineVulkan::InitDeviceObjects() {
assert(VK_SUCCESS == res);
VkDescriptorPoolSize dpTypes[2];
dpTypes[0].descriptorCount = 4096;
dpTypes[0].descriptorCount = 8192;
dpTypes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
dpTypes[1].descriptorCount = 2048;
dpTypes[1].descriptorCount = 8192 + 4096; // Due to the tess stuff, we need a LOT of these. Most will be empty...
dpTypes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
VkDescriptorPoolCreateInfo dp = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
@@ -200,7 +201,7 @@ void DrawEngineVulkan::InitDeviceObjects() {
samp.flags = 0;
samp.magFilter = VK_FILTER_NEAREST;
samp.minFilter = VK_FILTER_NEAREST;
res = vkCreateSampler(device, &samp, nullptr, &depalSampler_);
res = vkCreateSampler(device, &samp, nullptr, &samplerSecondary_);
res = vkCreateSampler(device, &samp, nullptr, &nullSampler_);
assert(VK_SUCCESS == res);
@@ -240,11 +241,11 @@ void DrawEngineVulkan::FrameData::Destroy(VulkanContext *vulkan) {
}
void DrawEngineVulkan::DestroyDeviceObjects() {
for (int i = 0; i < 2; i++) {
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
frame_[i].Destroy(vulkan_);
}
if (depalSampler_ != VK_NULL_HANDLE)
vulkan_->Delete().QueueDeleteSampler(depalSampler_);
if (samplerSecondary_ != VK_NULL_HANDLE)
vulkan_->Delete().QueueDeleteSampler(samplerSecondary_);
if (nullSampler_ != VK_NULL_HANDLE)
vulkan_->Delete().QueueDeleteSampler(nullSampler_);
if (pipelineLayout_ != VK_NULL_HANDLE)
@@ -275,10 +276,10 @@ void DrawEngineVulkan::DeviceRestore(VulkanContext *vulkan) {
}
void DrawEngineVulkan::BeginFrame() {
lastCmd_ = VK_NULL_HANDLE;
lastPipeline_ = nullptr;
FrameData *frame = &frame_[curFrame_];
int curFrame = vulkan_->GetCurFrame();
FrameData *frame = &frame_[curFrame];
// First reset all buffers, then begin. This is so that Reset can free memory and Begin can allocate it,
// if growing the buffer is needed. Doing it this way will reduce fragmentation if more than one buffer
@@ -294,10 +295,12 @@ void DrawEngineVulkan::BeginFrame() {
// TODO : Find a better place to do this.
if (!nullTexture_) {
ILOG("INIT : Creating null texture");
VkCommandBuffer cmdInit = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
nullTexture_ = new VulkanTexture(vulkan_);
int w = 8;
int h = 8;
nullTexture_->CreateDirect(w, h, 1, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
nullTexture_->CreateDirect(cmdInit, w, h, 1, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
uint32_t bindOffset;
VkBuffer bindBuf;
@@ -308,8 +311,8 @@ void DrawEngineVulkan::BeginFrame() {
data[y*w + x] = 0; // black
}
}
nullTexture_->UploadMip(0, w, h, bindBuf, bindOffset, w);
nullTexture_->EndCreate();
nullTexture_->UploadMip(cmdInit, 0, w, h, bindBuf, bindOffset, w);
nullTexture_->EndCreate(cmdInit);
}
DirtyAllUBOs();
@@ -355,16 +358,13 @@ void DrawEngineVulkan::BeginFrame() {
}
void DrawEngineVulkan::EndFrame() {
FrameData *frame = &frame_[curFrame_];
FrameData *frame = &frame_[vulkan_->GetCurFrame()];
stats_.pushUBOSpaceUsed = (int)frame->pushUBO->GetOffset();
stats_.pushVertexSpaceUsed = (int)frame->pushVertex->GetOffset();
stats_.pushIndexSpaceUsed = (int)frame->pushIndex->GetOffset();
frame->pushUBO->End();
frame->pushVertex->End();
frame->pushIndex->End();
curFrame_++;
if (curFrame_ >= vulkan_->GetInflightFrames())
curFrame_ = 0;
vertexCache_->End();
}
@@ -505,12 +505,11 @@ void DrawEngineVulkan::DecodeVerts(VulkanPushBuffer *push, uint32_t *bindOffset,
}
}
VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView, VkSampler sampler, VkBuffer base, VkBuffer light, VkBuffer bone) {
DescriptorSetKey key;
key.imageView_ = imageView;
key.sampler_ = sampler;
key.secondaryImageView_ = VK_NULL_HANDLE;
key.secondaryImageView_ = boundSecondary_;
key.base_ = base;
key.light_ = light;
key.bone_ = bone;
@@ -518,7 +517,7 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
assert(light != VK_NULL_HANDLE);
assert(bone != VK_NULL_HANDLE);
FrameData *frame = &frame_[curFrame_];
FrameData *frame = &frame_[vulkan_->GetCurFrame()];
if (!gstate_c.bezier && !gstate_c.spline) { // Has no cache when HW tessellation.
VkDescriptorSet d = frame->descSets.Get(key);
if (d != VK_NULL_HANDLE)
@@ -535,7 +534,8 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
descAlloc.descriptorPool = frame->descPool;
descAlloc.descriptorSetCount = 1;
VkResult result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, &desc);
assert(result == VK_SUCCESS);
// Even in release mode, this is bad.
_assert_msg_(G3D, result == VK_SUCCESS, "Ran out of descriptors in pool. sz=%d", (int)frame->descSets.size());
// We just don't write to the slots we don't care about.
VkWriteDescriptorSet writes[7];
@@ -558,6 +558,21 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
n++;
}
if (boundSecondary_) {
// TODO: Also support LAYOUT_GENERAL to be able to texture from framebuffers without transitioning them?
tex.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
tex.imageView = boundSecondary_;
tex.sampler = samplerSecondary_;
writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writes[n].pNext = nullptr;
writes[n].dstBinding = DRAW_BINDING_2ND_TEXTURE;
writes[n].pImageInfo = &tex;
writes[n].descriptorCount = 1;
writes[n].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writes[n].dstSet = desc;
n++;
}
// Skipping 2nd texture for now.
// Tessellation data textures
@@ -643,19 +658,14 @@ void DrawEngineVulkan::DoFlush() {
// TODO: Should be enough to update this once per frame?
gpuStats.numTrackedVertexArrays = (int)vai_.size();
VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::RENDERPASS_COMMANDBUFFER);
if (cmd != lastCmd_) {
lastPipeline_ = nullptr;
lastCmd_ = cmd;
// Since we have a new cmdbuf, dirty our dynamic state so it gets re-set.
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE|DIRTY_DEPTHSTENCIL_STATE|DIRTY_BLEND_STATE);
}
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
// HACK: These two lines should only execute if we started on a new render pass. Can't tell from in here though...
lastPipeline_ = nullptr;
// Since we have a new cmdbuf, dirty our dynamic state so it gets re-set.
// gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE|DIRTY_DEPTHSTENCIL_STATE|DIRTY_BLEND_STATE);
VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::CURRENT_RENDERPASS);
if (!rp)
Crash();
FrameData *frame = &frame_[curFrame_];
FrameData *frame = &frame_[vulkan_->GetCurFrame()];
bool textureNeedsApply = false;
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
@@ -870,23 +880,28 @@ void DrawEngineVulkan::DoFlush() {
sampler = nullSampler_;
}
if (!lastPipeline_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) {
if (!lastPipeline_ || !gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) {
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform);
if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) {
ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_);
}
VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS);
Draw::NativeObject object = g_Config.iRenderingMode != 0 ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS;
VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object);
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, true);
if (!pipeline) {
// Already logged, let's bail out.
return;
}
renderManager->BindPipeline(pipeline->pipeline);
if (pipeline != lastPipeline_) {
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline);
if (lastPipeline_ && !lastPipeline_->useBlendConstant && pipeline->useBlendConstant) {
gstate_c.Dirty(DIRTY_BLEND_STATE);
}
lastPipeline_ = pipeline;
}
ApplyDrawStateLate(cmd, false, 0);
ApplyDrawStateLate(renderManager, false, 0, pipeline->useBlendConstant);
gstate_c.Clean(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
lastPipeline_ = pipeline;
}
lastPrim_ = prim;
@@ -894,30 +909,22 @@ void DrawEngineVulkan::DoFlush() {
UpdateUBOs(frame);
VkDescriptorSet ds = GetOrCreateDescriptorSet(imageView, sampler, baseBuf, lightBuf, boneBuf);
{
PROFILE_THIS_SCOPE("vkdraw");
PROFILE_THIS_SCOPE("renderman_q");
const uint32_t dynamicUBOOffsets[3] = {
baseUBOOffset, lightUBOOffset, boneUBOOffset,
};
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &ds, 3, dynamicUBOOffsets);
int stride = dec_->GetDecVtxFmt().stride;
VkDeviceSize offsets[1] = { vbOffset };
if (useElements) {
if (!ibuf)
ibOffset = (uint32_t)frame->pushIndex->Push(decIndex, sizeof(uint16_t) * indexGen.VertexCount(), &ibuf);
// TODO (maybe): Avoid rebinding vertex/index buffers if the vertex size stays the same by using the offset arguments.
// Not sure if actually worth it, binding buffers should be fast.
vkCmdBindVertexBuffers(cmd, 0, 1, &vbuf, offsets);
vkCmdBindIndexBuffer(cmd, ibuf, ibOffset, VK_INDEX_TYPE_UINT16);
int numInstances = (gstate_c.bezier || gstate_c.spline) ? numPatches : 1;
vkCmdDrawIndexed(cmd, vertexCount, numInstances, 0, 0, 0);
renderManager->DrawIndexed(pipelineLayout_, ds, 3, dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, vertexCount, numInstances, VK_INDEX_TYPE_UINT16);
} else {
vkCmdBindVertexBuffers(cmd, 0, 1, &vbuf, offsets);
vkCmdDraw(cmd, vertexCount, 1, 0, 0);
renderManager->Draw(pipelineLayout_, ds, 3, dynamicUBOOffsets, vbuf, vbOffset, vertexCount);
}
}
} else {
@@ -971,24 +978,28 @@ void DrawEngineVulkan::DoFlush() {
if (sampler == VK_NULL_HANDLE)
sampler = nullSampler_;
}
if (!lastPipeline_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) {
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform);
if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) {
ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_);
}
VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS);
Draw::NativeObject object = g_Config.iRenderingMode != 0 ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS;
VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object);
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, false);
renderManager->BindPipeline(pipeline->pipeline);
if (!pipeline) {
// Already logged, let's bail out.
return;
}
if (pipeline != lastPipeline_) {
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline); // TODO: Avoid if same as last draw.
if (lastPipeline_ && !lastPipeline_->useBlendConstant && pipeline->useBlendConstant) {
gstate_c.Dirty(DIRTY_BLEND_STATE);
}
lastPipeline_ = pipeline;
}
ApplyDrawStateLate(cmd, false, 0);
ApplyDrawStateLate(renderManager, false, 0, pipeline->useBlendConstant);
gstate_c.Clean(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
lastPipeline_ = pipeline;
}
lastPrim_ = prim;
@@ -1002,25 +1013,19 @@ void DrawEngineVulkan::DoFlush() {
baseUBOOffset, lightUBOOffset, boneUBOOffset,
};
PROFILE_THIS_SCOPE("vkdrawsoft");
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &ds, 3, dynamicUBOOffsets);
PROFILE_THIS_SCOPE("renderman_q");
if (drawIndexed) {
VkBuffer vbuf, ibuf;
vbOffset = (uint32_t)frame->pushVertex->Push(drawBuffer, maxIndex * sizeof(TransformedVertex), &vbuf);
ibOffset = (uint32_t)frame->pushIndex->Push(inds, sizeof(short) * numTrans, &ibuf);
VkDeviceSize offsets[1] = { vbOffset };
// TODO: Avoid rebinding if the vertex size stays the same by using the offset arguments
vkCmdBindVertexBuffers(cmd, 0, 1, &vbuf, offsets);
vkCmdBindIndexBuffer(cmd, ibuf, ibOffset, VK_INDEX_TYPE_UINT16);
vkCmdDrawIndexed(cmd, numTrans, 1, 0, 0, 0);
renderManager->DrawIndexed(pipelineLayout_, ds, 3, dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, numTrans, 1, VK_INDEX_TYPE_UINT16);
} else {
VkBuffer vbuf;
vbOffset = (uint32_t)frame->pushVertex->Push(drawBuffer, numTrans * sizeof(TransformedVertex), &vbuf);
VkDeviceSize offsets[1] = { vbOffset };
// TODO: Avoid rebinding if the vertex size stays the same by using the offset arguments
vkCmdBindVertexBuffers(cmd, 0, 1, &vbuf, offsets);
vkCmdDraw(cmd, numTrans, 1, 0, 0);
renderManager->Draw(pipelineLayout_, ds, 3, dynamicUBOOffsets, vbuf, vbOffset, numTrans);
}
} else if (result.action == SW_CLEAR) {
// Note: we won't get here if the clear is alpha but not color, or color but not alpha.
@@ -1078,18 +1083,16 @@ void DrawEngineVulkan::UpdateUBOs(FrameData *frame) {
}
}
bool DrawEngineVulkan::IsCodePtrVertexDecoder(const u8 *ptr) const {
return decJitCache_->IsInSpace(ptr);
}
void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&pos, float *&tex, float *&col, int size, bool hasColor, bool hasTexCoords) {
int rowPitch;
ILOG("INIT : Prep tess");
VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
// Position
if (prevSize < size) {
prevSize = size;
data_tex[0]->CreateDirect(size, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
data_tex[0]->CreateDirect(cmd, size, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
}
pos = (float *)data_tex[0]->Lock(0, &rowPitch);
@@ -1098,7 +1101,7 @@ void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&po
if (prevSizeTex < size) {
prevSizeTex = size;
data_tex[1]->CreateDirect(size, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
data_tex[1]->CreateDirect(cmd, size, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
}
tex = (float *)data_tex[1]->Lock(0, &rowPitch);
}
@@ -1108,19 +1111,20 @@ void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&po
if (prevSizeCol < sizeColor) {
prevSizeCol = sizeColor;
data_tex[2]->CreateDirect(sizeColor, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
data_tex[2]->CreateDirect(cmd, sizeColor, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
}
col = (float *)data_tex[2]->Lock(0, &rowPitch);
}
void DrawEngineVulkan::TessellationDataTransferVulkan::SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) {
VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
// Position
data_tex[0]->Unlock();
data_tex[0]->Unlock(cmd);
// Texcoords
if (hasTexCoords)
data_tex[1]->Unlock();
data_tex[1]->Unlock(cmd);
// Color
data_tex[2]->Unlock();
data_tex[2]->Unlock(cmd);
}
+22 -16
View File
@@ -113,6 +113,8 @@ public:
u8 flags = 0;
};
class VulkanRenderManager;
// Handles transform, lighting and drawing.
class DrawEngineVulkan : public DrawEngineCommon {
public:
@@ -147,8 +149,6 @@ public:
DoFlush();
}
bool IsCodePtrVertexDecoder(const u8 *ptr) const;
void DispatchFlush() override { Flush(); }
void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) override {
SubmitPrim(verts, inds, prim, vertexCount, vertType, bytesRead);
@@ -163,8 +163,12 @@ public:
void DirtyAllUBOs();
void DirtyPipeline() {
lastPipeline_ = nullptr;
}
VulkanPushBuffer *GetPushBufferForTextureData() {
return frame_[curFrame_].pushUBO;
return frame_[vulkan_->GetCurFrame()].pushUBO;
}
const DrawEngineVulkanStats &GetStats() const {
@@ -173,8 +177,9 @@ public:
private:
struct FrameData;
void ApplyDrawStateLate(VkCommandBuffer cmd, bool applyStencilRef, uint8_t stencilRef);
void ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant);
void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerVulkan *shaderManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &dynState);
void ResetShaderBlending();
void InitDeviceObjects();
void DestroyDeviceObjects();
@@ -193,10 +198,13 @@ private:
// We use a single descriptor set layout for all PSP draws.
VkDescriptorSetLayout descriptorSetLayout_;
VkPipelineLayout pipelineLayout_;
VkCommandBuffer lastCmd_ = VK_NULL_HANDLE;
VulkanPipeline *lastPipeline_;
VkDescriptorSet lastDs_ = VK_NULL_HANDLE;
// Secondary texture for shader blending
VkImageView boundSecondary_ = VK_NULL_HANDLE;
VkSampler samplerSecondary_ = VK_NULL_HANDLE;
PrehashMap<VertexArrayInfoVulkan *, nullptr> vai_;
VulkanPushBuffer *vertexCache_;
int decimationCounter_ = 0;
@@ -225,7 +233,6 @@ private:
};
GEPrimitiveType lastPrim_ = GE_PRIM_INVALID;
int curFrame_;
FrameData frame_[VulkanContext::MAX_INFLIGHT_FRAMES];
// Other
@@ -234,16 +241,14 @@ private:
TextureCacheVulkan *textureCache_ = nullptr;
FramebufferManagerVulkan *framebufferManager_ = nullptr;
VkSampler depalSampler_;
// State cache
uint64_t dirtyUniforms_;
uint32_t baseUBOOffset;
uint32_t lightUBOOffset;
uint32_t boneUBOOffset;
VkBuffer baseBuf, lightBuf, boneBuf;
VkImageView imageView;
VkSampler sampler;
VkImageView imageView = VK_NULL_HANDLE;
VkSampler sampler = VK_NULL_HANDLE;
// Null texture
VulkanTexture *nullTexture_ = nullptr;
@@ -257,14 +262,15 @@ private:
// Hardware tessellation
class TessellationDataTransferVulkan : public TessellationDataTransfer {
private:
VulkanContext *vulkan;
VulkanContext *vulkan_;
Draw::DrawContext *draw_;
VulkanTexture *data_tex[3];
VkSampler sampler;
public:
TessellationDataTransferVulkan(VulkanContext *vulkan)
: TessellationDataTransfer(), vulkan(vulkan), data_tex(), sampler() {
TessellationDataTransferVulkan(VulkanContext *vulkan, Draw::DrawContext *draw)
: TessellationDataTransfer(), vulkan_(vulkan), draw_(draw), data_tex(), sampler() {
for (int i = 0; i < 3; i++)
data_tex[i] = new VulkanTexture(vulkan);
data_tex[i] = new VulkanTexture(vulkan_);
CreateSampler();
}
@@ -272,7 +278,7 @@ private:
for (int i = 0; i < 3; i++)
delete data_tex[i];
vulkan->Delete().QueueDeleteSampler(sampler);
vulkan_->Delete().QueueDeleteSampler(sampler);
}
void SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) override;
void PrepareBuffers(float *&pos, float *&tex, float *&col, int size, bool hasColor, bool hasTexCoords) override;
@@ -303,7 +309,7 @@ private:
samp.minLod = 0.0f;
samp.mipLodBias = 0.0f;
VkResult res = vkCreateSampler(vulkan->GetDevice(), &samp, nullptr, &sampler);
VkResult res = vkCreateSampler(vulkan_->GetDevice(), &samp, nullptr, &sampler);
assert(res == VK_SUCCESS);
}
};
+76 -564
View File
@@ -28,6 +28,7 @@
#include "Common/Vulkan/VulkanContext.h"
#include "Common/Vulkan/VulkanMemory.h"
#include "Common/Vulkan/VulkanImage.h"
#include "thin3d/VulkanRenderManager.h"
#include "Common/ColorConv.h"
#include "Core/Host.h"
#include "Core/MemMap.h"
@@ -87,19 +88,18 @@ FramebufferManagerVulkan::FramebufferManagerVulkan(Draw::DrawContext *draw, Vulk
convBufSize_(0),
textureCacheVulkan_(nullptr),
shaderManagerVulkan_(nullptr),
pixelBufObj_(nullptr),
currentPBO_(0),
curFrame_(0),
pipelinePostShader_(VK_NULL_HANDLE),
vulkan2D_(vulkan) {
depalVulkan_(draw, vulkan) {
InitDeviceObjects();
// After a blit we do need to rebind for the VulkanRenderManager to know what to do.
needGLESRebinds_ = true;
}
FramebufferManagerVulkan::~FramebufferManagerVulkan() {
delete[] convBuf_;
vulkan2D_.Shutdown();
DestroyDeviceObjects();
}
@@ -113,24 +113,18 @@ void FramebufferManagerVulkan::SetShaderManager(ShaderManagerVulkan *sm) {
shaderManager_ = sm;
}
void FramebufferManagerVulkan::SetDrawEngine(DrawEngineVulkan *td) {
drawEngineVulkan_ = td;
drawEngine_ = td;
}
void FramebufferManagerVulkan::InitDeviceObjects() {
// Initialize framedata
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
frameData_[i].push_ = new VulkanPushBuffer(vulkan_, 64 * 1024);
}
pipelineCache2D_ = vulkan_->CreatePipelineCache();
std::string fs_errors, vs_errors;
fsBasicTex_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_FRAGMENT_BIT, tex_fs, &fs_errors);
vsBasicTex_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_VERTEX_BIT, tex_vs, &vs_errors);
assert(fsBasicTex_ != VK_NULL_HANDLE);
assert(vsBasicTex_ != VK_NULL_HANDLE);
// Prime the 2D pipeline cache.
vulkan2D_.GetPipeline(pipelineCache2D_, vulkan_->GetSurfaceRenderPass(), vsBasicTex_, fsBasicTex_);
vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS), vsBasicTex_, fsBasicTex_);
VkSamplerCreateInfo samp = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
samp.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samp.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
@@ -146,13 +140,6 @@ void FramebufferManagerVulkan::InitDeviceObjects() {
}
void FramebufferManagerVulkan::DestroyDeviceObjects() {
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
if (frameData_[i].push_) {
frameData_[i].push_->Destroy(vulkan_);
delete frameData_[i].push_;
frameData_[i].push_ = nullptr;
}
}
delete drawPixelsTex_;
drawPixelsTex_ = nullptr;
@@ -160,41 +147,38 @@ void FramebufferManagerVulkan::DestroyDeviceObjects() {
vulkan_->Delete().QueueDeleteShaderModule(fsBasicTex_);
if (vsBasicTex_ != VK_NULL_HANDLE)
vulkan_->Delete().QueueDeleteShaderModule(vsBasicTex_);
if (stencilFs_ != VK_NULL_HANDLE)
vulkan_->Delete().QueueDeleteShaderModule(stencilFs_);
if (stencilVs_ != VK_NULL_HANDLE)
vulkan_->Delete().QueueDeleteShaderModule(stencilVs_);
if (linearSampler_ != VK_NULL_HANDLE)
vulkan_->Delete().QueueDeleteSampler(linearSampler_);
if (nearestSampler_ != VK_NULL_HANDLE)
vulkan_->Delete().QueueDeleteSampler(nearestSampler_);
// pipelineBasicTex_ and pipelineBasicTex_ come from vulkan2D_.
if (pipelineCache2D_ != VK_NULL_HANDLE)
vulkan_->Delete().QueueDeletePipelineCache(pipelineCache2D_);
}
void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth) {
// if (!useBufferedRendering_) {
float x, y, w, h;
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL);
float x, y, w, h;
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL);
int mask = 0;
// The Clear detection takes care of doing a regular draw instead if separate masking
// of color and alpha is needed, so we can just treat them as the same.
if (clearColor || clearAlpha)
mask |= Draw::FBChannel::FB_COLOR_BIT;
if (clearDepth)
mask |= Draw::FBChannel::FB_DEPTH_BIT;
if (clearAlpha)
mask |= Draw::FBChannel::FB_STENCIL_BIT;
int mask = 0;
// The Clear detection takes care of doing a regular draw instead if separate masking
// of color and alpha is needed, so we can just treat them as the same.
if (clearColor || clearAlpha)
mask |= Draw::FBChannel::FB_COLOR_BIT;
if (clearDepth)
mask |= Draw::FBChannel::FB_DEPTH_BIT;
if (clearAlpha)
mask |= Draw::FBChannel::FB_STENCIL_BIT;
draw_->Clear(mask, color, depth, 0);
if (clearColor || clearAlpha) {
SetColorUpdated(gstate_c.skipDrawReason);
}
if (clearDepth) {
SetDepthUpdated();
}
//} else {
// TODO: Clever render pass magic.
//}
draw_->Clear(mask, color, depth, 0);
if (clearColor || clearAlpha) {
SetColorUpdated(gstate_c.skipDrawReason);
}
if (clearDepth) {
SetDepthUpdated();
}
}
void FramebufferManagerVulkan::UpdatePostShaderUniforms(int bufferWidth, int bufferHeight, int renderWidth, int renderHeight) {
@@ -226,22 +210,27 @@ void FramebufferManagerVulkan::Init() {
}
void FramebufferManagerVulkan::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) {
if (drawPixelsTex_ && (drawPixelsTexFormat_ != srcPixelFormat || drawPixelsTex_->GetWidth() != width || drawPixelsTex_->GetHeight() != height)) {
if (drawPixelsTex_) {
delete drawPixelsTex_;
drawPixelsTex_ = nullptr;
}
if (!drawPixelsTex_) {
drawPixelsTex_ = new VulkanTexture(vulkan_);
drawPixelsTex_->CreateDirect(width, height, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
// Initialize backbuffer texture for DrawPixels
drawPixelsTexFormat_ = srcPixelFormat;
} else {
drawPixelsTex_->TransitionForUpload();
VkCommandBuffer initCmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
drawPixelsTex_ = new VulkanTexture(vulkan_);
if (!drawPixelsTex_->CreateDirect(initCmd, width, height, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)) {
// out of memory?
delete drawPixelsTex_;
drawPixelsTex_ = nullptr;
overrideImageView_ = VK_NULL_HANDLE;
return;
}
// Initialize backbuffer texture for DrawPixels
drawPixelsTexFormat_ = srcPixelFormat;
// TODO: We can just change the texture format and flip some bits around instead of this.
// Could share code with the texture cache perhaps.
// Could also convert directly into the pushbuffer easily.
const uint8_t *data = srcPixels;
if (srcPixelFormat != GE_FORMAT_8888 || srcStride != width) {
u32 neededSize = width * height * 4;
@@ -293,26 +282,23 @@ void FramebufferManagerVulkan::MakePixelTexture(const u8 *srcPixels, GEBufferFor
}
VkBuffer buffer;
size_t offset = frameData_[curFrame_].push_->Push(data, width * height * 4, &buffer);
drawPixelsTex_->UploadMip(0, width, height, buffer, (uint32_t)offset, width);
drawPixelsTex_->EndCreate();
size_t offset = push_->Push(data, width * height * 4, &buffer);
drawPixelsTex_->UploadMip(initCmd, 0, width, height, buffer, (uint32_t)offset, width);
drawPixelsTex_->EndCreate(initCmd);
overrideImageView_ = drawPixelsTex_->GetImageView();
}
void FramebufferManagerVulkan::SetViewport2D(int x, int y, int w, int h) {
VkViewport vp;
vp.minDepth = 0.0;
vp.maxDepth = 1.0;
vp.x = (float)x;
vp.y = (float)y;
vp.width = (float)w;
vp.height = (float)h;
Draw::Viewport vp;
vp.MinDepth = 0.0;
vp.MaxDepth = 1.0;
vp.TopLeftX = (float)x;
vp.TopLeftY = (float)y;
vp.Width = (float)w;
vp.Height = (float)h;
// Since we're about to override it.
draw_->FlushState();
VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::RENDERPASS_COMMANDBUFFER);
vkCmdSetViewport(cmd, 0, 1, &vp);
draw_->SetViewports(1, &vp);
}
void FramebufferManagerVulkan::DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) {
@@ -355,24 +341,21 @@ void FramebufferManagerVulkan::DrawActiveTexture(float x, float y, float w, floa
// TODO: Should probably use draw_ directly and not go low level
VulkanPushBuffer *push = frameData_[curFrame_].push_;
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::RENDERPASS_COMMANDBUFFER);
VkImageView view = overrideImageView_ ? overrideImageView_ : (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE_IMAGEVIEW);
VkImageView view = overrideImageView_ ? overrideImageView_ : (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW);
if ((flags & DRAWTEX_KEEP_TEX) == 0)
overrideImageView_ = VK_NULL_HANDLE;
vulkan2D_.BindDescriptorSet(cmd, view, (flags & DRAWTEX_LINEAR) ? linearSampler_ : nearestSampler_);
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, cur2DPipeline_);
VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(view, (flags & DRAWTEX_LINEAR) ? linearSampler_ : nearestSampler_, VK_NULL_HANDLE, VK_NULL_HANDLE);
VkBuffer vbuffer;
VkDeviceSize offset = push->Push(vtx, sizeof(vtx), &vbuffer);
vkCmdBindVertexBuffers(cmd, 0, 1, &vbuffer, &offset);
vkCmdDraw(cmd, 4, 1, 0, 0);
VkDeviceSize offset = push_->Push(vtx, sizeof(vtx), &vbuffer);
renderManager->BindPipeline(cur2DPipeline_);
renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, vbuffer, offset, 4);
}
void FramebufferManagerVulkan::Bind2DShader() {
VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS);
cur2DPipeline_ = vulkan2D_.GetPipeline(pipelineCache2D_, rp, vsBasicTex_, fsBasicTex_);
cur2DPipeline_ = vulkan2D_->GetPipeline(rp, vsBasicTex_, fsBasicTex_);
}
void FramebufferManagerVulkan::BindPostShader(const PostShaderUniforms &uniforms) {
@@ -387,12 +370,7 @@ void FramebufferManagerVulkan::RebindFramebuffer() {
// Should this even happen?
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP });
}
}
bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skipZero) {
// In Vulkan we should be able to simply copy the stencil data directly to a stencil buffer without
// messing about with bitplane textures and the like.
return false;
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE);
}
int FramebufferManagerVulkan::GetLineWidth() {
@@ -434,13 +412,15 @@ void FramebufferManagerVulkan::BlitFramebufferDepth(VirtualFramebuffer *src, Vir
bool matchingDepthBuffer = src->z_address == dst->z_address && src->z_stride != 0 && dst->z_stride != 0;
bool matchingSize = src->width == dst->width && src->height == dst->height;
bool matchingRenderSize = src->renderWidth == dst->renderWidth && src->renderHeight == dst->renderHeight;
if (gstate_c.Supports(GPU_SUPPORTS_ANY_COPY_IMAGE) && matchingDepthBuffer && matchingRenderSize && matchingSize) {
if (matchingDepthBuffer && matchingRenderSize && matchingSize) {
// TODO: Currently, this copies depth AND stencil, which is a problem. See #9740.
draw_->CopyFramebufferImage(src->fbo, 0, 0, 0, 0, dst->fbo, 0, 0, 0, 0, src->renderWidth, src->renderHeight, 1, Draw::FB_DEPTH_BIT);
} else if (matchingDepthBuffer && matchingSize) {
/*
int w = std::min(src->renderWidth, dst->renderWidth);
int h = std::min(src->renderHeight, dst->renderHeight);
draw_->BlitFramebuffer(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST);
*/
}
}
@@ -458,10 +438,6 @@ VkImageView FramebufferManagerVulkan::BindFramebufferAsColorTexture(int stage, V
}
// Currently rendering to this framebuffer. Need to make a copy.
if (!skipCopy && framebuffer == currentRenderVfb_) {
// ignore this case for now, doesn't work
// ILOG("Texturing from current render Vfb!");
return VK_NULL_HANDLE;
// TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size.
Draw::Framebuffer *renderCopy = GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, (Draw::FBColorDepth)framebuffer->colorDepth);
if (renderCopy) {
@@ -473,10 +449,10 @@ VkImageView FramebufferManagerVulkan::BindFramebufferAsColorTexture(int stage, V
} else {
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0);
}
return (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE_IMAGEVIEW);
return (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW);
} else if (framebuffer != currentRenderVfb_) {
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0);
return (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE_IMAGEVIEW);
return (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW);
} else {
ERROR_LOG_REPORT_ONCE(vulkanSelfTexture, G3D, "Attempting to texture from target");
// To do this safely in Vulkan, we need to use input attachments.
@@ -484,174 +460,21 @@ VkImageView FramebufferManagerVulkan::BindFramebufferAsColorTexture(int stage, V
}
}
VulkanTexture *FramebufferManagerVulkan::GetFramebufferColor(u32 fbRawAddress, VirtualFramebuffer *framebuffer, int flags) {
if (framebuffer == NULL) {
framebuffer = currentRenderVfb_;
}
if (!framebuffer->fbo || !useBufferedRendering_) {
gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE;
return nullptr;
}
// currentRenderVfb_ will always be set when this is called, except from the GE debugger.
// Let's just not bother with the copy in that case.
bool skipCopy = (flags & BINDFBCOLOR_MAY_COPY) == 0;
if (GPUStepping::IsStepping() || g_Config.bDisableSlowFramebufEffects) {
skipCopy = true;
}
if (!skipCopy && currentRenderVfb_ && framebuffer->fb_address == fbRawAddress) {
// TODO: Enable the below code
return nullptr; // framebuffer->fbo->GetColor();
/*
// TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size.
VulkanFBO *renderCopy = GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, (FBOColorDepth)framebuffer->colorDepth);
if (renderCopy) {
VirtualFramebuffer copyInfo = *framebuffer;
copyInfo.fbo = renderCopy;
int x = 0;
int y = 0;
int w = framebuffer->drawnWidth;
int h = framebuffer->drawnHeight;
// If max is not > min, we probably could not detect it. Skip.
// See the vertex decoder, where this is updated.
if ((flags & BINDFBCOLOR_MAY_COPY_WITH_UV) == BINDFBCOLOR_MAY_COPY_WITH_UV && gstate_c.vertBounds.maxU > gstate_c.vertBounds.minU) {
x = gstate_c.vertBounds.minU;
y = gstate_c.vertBounds.minV;
w = gstate_c.vertBounds.maxU - x;
h = gstate_c.vertBounds.maxV - y;
// If we bound a framebuffer, apply the byte offset as pixels to the copy too.
if (flags & BINDFBCOLOR_APPLY_TEX_OFFSET) {
x += gstate_c.curTextureXOffset;
y += gstate_c.curTextureYOffset;
}
}
BlitFramebuffer(&copyInfo, x, y, framebuffer, x, y, w, h, 0);
return nullptr; // fbo_bind_color_as_texture(renderCopy, 0);
} else {
return framebuffer->fbo->GetColor();
}
*/
} else {
return nullptr; // framebuffer->fbo->GetColor();
}
}
void FramebufferManagerVulkan::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) {
PROFILE_THIS_SCOPE("gpu-readback");
if (sync) {
// flush async just in case when we go for synchronous update
// Doesn't actually pack when sent a null argument.
PackFramebufferAsync_(nullptr);
}
if (vfb) {
// We'll pseudo-blit framebuffers here to get a resized version of vfb.
VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb);
OptimizeDownloadRange(vfb, x, y, w, h);
BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0);
// PackFramebufferSync_() - Synchronous pixel data transfer using glReadPixels
// PackFramebufferAsync_() - Asynchronous pixel data transfer using glReadPixels with PBOs
// TODO: Can we fall back to sync without these?
if (!sync) {
PackFramebufferAsync_(nvfb);
} else {
PackFramebufferSync_(nvfb, x, y, w, h);
}
textureCacheVulkan_->ForgetLastTexture();
RebindFramebuffer();
}
}
void FramebufferManagerVulkan::DownloadFramebufferForClut(u32 fb_address, u32 loadBytes) {
PROFILE_THIS_SCOPE("gpu-readback");
// Flush async just in case.
PackFramebufferAsync_(nullptr);
VirtualFramebuffer *vfb = GetVFBAt(fb_address);
if (vfb && vfb->fb_stride != 0) {
const u32 bpp = vfb->drawnFormat == GE_FORMAT_8888 ? 4 : 2;
int x = 0;
int y = 0;
int pixels = loadBytes / bpp;
// The height will be 1 for each stride or part thereof.
int w = std::min(pixels % vfb->fb_stride, (int)vfb->width);
int h = std::min((pixels + vfb->fb_stride - 1) / vfb->fb_stride, (int)vfb->height);
// No need to download if we already have it.
if (!vfb->memoryUpdated && vfb->clutUpdatedBytes < loadBytes) {
// We intentionally don't call OptimizeDownloadRange() here - we don't want to over download.
// CLUT framebuffers are often incorrectly estimated in size.
if (x == 0 && y == 0 && w == vfb->width && h == vfb->height) {
vfb->memoryUpdated = true;
}
vfb->clutUpdatedBytes = loadBytes;
// We'll pseudo-blit framebuffers here to get a resized version of vfb.
VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb);
BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0);
PackFramebufferSync_(nvfb, x, y, w, h);
textureCacheVulkan_->ForgetLastTexture();
RebindFramebuffer();
}
}
}
bool FramebufferManagerVulkan::CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
// When updating VRAM, it need to be exact format.
if (!gstate_c.Supports(GPU_PREFER_CPU_DOWNLOAD)) {
switch (nvfb->format) {
case GE_FORMAT_4444:
nvfb->colorDepth = VK_FBO_4444;
break;
case GE_FORMAT_5551:
nvfb->colorDepth = VK_FBO_5551;
break;
case GE_FORMAT_565:
nvfb->colorDepth = VK_FBO_565;
break;
case GE_FORMAT_8888:
default:
nvfb->colorDepth = VK_FBO_8888;
break;
}
}
nvfb->colorDepth = Draw::FBO_8888;
/*
nvfb->fbo = CreateFramebuffer(nvfb->width, nvfb->height, 1, false, (FBOColorDepth)nvfb->colorDepth);
nvfb->fbo = draw_->CreateFramebuffer({ nvfb->width, nvfb->height, 1, 1, true, (Draw::FBColorDepth)nvfb->colorDepth });
if (!(nvfb->fbo)) {
ERROR_LOG(FRAMEBUF, "Error creating FBO! %i x %i", nvfb->renderWidth, nvfb->renderHeight);
return false;
}
BindFramebufferAsRenderTarget(nvfb->fbo);
*/
draw_->BindFramebufferAsRenderTarget(nvfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
return true;
}
void FramebufferManagerVulkan::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
// _assert_msg_(G3D, nvfb->fbo, "Expecting a valid nvfb in UpdateDownloadTempBuffer");
// Discard the previous contents of this buffer where possible.
/*
if (gl_extensions.GLES3 && glInvalidateFramebuffer != nullptr) {
BindFramebufferAsRenderTargetnvfb->fbo);
GLenum attachments[3] = { GL_COLOR_ATTACHMENT0, GL_STENCIL_ATTACHMENT, GL_DEPTH_ATTACHMENT };
glInvalidateFramebuffer(GL_FRAMEBUFFER, 3, attachments);
} else if (gl_extensions.IsGLES) {
BindFramebufferAsRenderTargetnvfb->fbo);
}
*/
// Nothing to do here.
}
void FramebufferManagerVulkan::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) {
@@ -756,205 +579,15 @@ void ConvertFromRGBA8888_Vulkan(u8 *dst, const u8 *src, u32 dstStride, u32 srcSt
}
}
#ifdef DEBUG_READ_PIXELS
// TODO: Make more generic.
static void LogReadPixelsError(GLenum error) {
switch (error) {
case GL_NO_ERROR:
break;
case GL_INVALID_ENUM:
ERROR_LOG(FRAMEBUF, "glReadPixels: GL_INVALID_ENUM");
break;
case GL_INVALID_VALUE:
ERROR_LOG(FRAMEBUF, "glReadPixels: GL_INVALID_VALUE");
break;
case GL_INVALID_OPERATION:
ERROR_LOG(FRAMEBUF, "glReadPixels: GL_INVALID_OPERATION");
break;
case GL_INVALID_FRAMEBUFFER_OPERATION:
ERROR_LOG(FRAMEBUF, "glReadPixels: GL_INVALID_FRAMEBUFFER_OPERATION");
break;
case GL_OUT_OF_MEMORY:
ERROR_LOG(FRAMEBUF, "glReadPixels: GL_OUT_OF_MEMORY");
break;
#ifndef USING_GLES2
case GL_STACK_UNDERFLOW:
ERROR_LOG(FRAMEBUF, "glReadPixels: GL_STACK_UNDERFLOW");
break;
case GL_STACK_OVERFLOW:
ERROR_LOG(FRAMEBUF, "glReadPixels: GL_STACK_OVERFLOW");
break;
#endif
default:
ERROR_LOG(FRAMEBUF, "glReadPixels: %08x", error);
break;
}
}
#endif
// One frame behind, but no stalling.
void FramebufferManagerVulkan::PackFramebufferAsync_(VirtualFramebuffer *vfb) {
const int MAX_PBO = 2;
uint8_t *packed = 0;
const u8 nextPBO = (currentPBO_ + 1) % MAX_PBO;
bool useCPU = false;
// We'll prepare two PBOs to switch between readying and reading
if (!pixelBufObj_) {
if (!vfb) {
// This call is just to flush the buffers. We don't have any yet,
// so there's nothing to do.
return;
}
// GLuint pbos[MAX_PBO];
// glGenBuffers(MAX_PBO, pbos);
pixelBufObj_ = new AsyncPBOVulkan[MAX_PBO];
for (int i = 0; i < MAX_PBO; i++) {
// TODO
// pixelBufObj_[i].handle = pbos[i];
pixelBufObj_[i].maxSize = 0;
pixelBufObj_[i].reading = false;
}
}
// Receive previously requested data from a PBO
AsyncPBOVulkan &pbo = pixelBufObj_[nextPBO];
if (pbo.reading) {
// glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle);
// packed = (GLubyte *)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, pbo.size, GL_MAP_READ_BIT);
if (packed) {
DEBUG_LOG(FRAMEBUF, "Reading PBO to memory , bufSize = %u, packed = %p, fb_address = %08x, stride = %u, pbo = %u",
pbo.size, packed, pbo.fb_address, pbo.stride, nextPBO);
// We don't need to convert, GPU already did (or should have)
// (vulkan: hopefully)
Memory::MemcpyUnchecked(pbo.fb_address, packed, pbo.size);
pbo.reading = false;
}
// glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
}
// Order packing/readback of the framebuffer
if (vfb) {
// int pixelType, pixelFormat;
int pixelSize, align;
switch (vfb->format) {
case GE_FORMAT_4444: // 16 bit RGBA
// pixelType = GL_UNSIGNED_SHORT_4_4_4_4;
// pixelFormat = GL_RGBA;
pixelSize = 2;
align = 2;
break;
case GE_FORMAT_5551: // 16 bit RGBA
// pixelType = GL_UNSIGNED_SHORT_5_5_5_1;
// pixelFormat = GL_RGBA;
pixelSize = 2;
align = 2;
break;
case GE_FORMAT_565: // 16 bit RGB
// pixelType = GL_UNSIGNED_SHORT_5_6_5;
// pixelFormat = GL_RGB;
pixelSize = 2;
align = 2;
break;
case GE_FORMAT_8888: // 32 bit RGBA
default:
// pixelType = GL_UNSIGNED_BYTE;
// pixelFormat = UseBGRA8888() ? GL_BGRA_EXT : GL_RGBA;
pixelSize = 4;
align = 4;
break;
}
// If using the CPU, we need 4 bytes per pixel always.
u32 bufSize = vfb->fb_stride * vfb->height * 4 * (useCPU ? 4 : pixelSize);
u32 fb_address = (0x04000000) | vfb->fb_address;
if (vfb->fbo) {
// fbo_bind_for_read(vfb->fbo);
} else {
ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackFramebufferAsync_: vfb->fbo == 0");
// fbo_unbind_read();
return;
}
// glBindBuffer(GL_PIXEL_PACK_BUFFER, pixelBufObj_[currentPBO_].handle);
if (pixelBufObj_[currentPBO_].maxSize < bufSize) {
// We reserve a buffer big enough to fit all those pixels
// glBufferData(GL_PIXEL_PACK_BUFFER, bufSize, NULL, GL_DYNAMIC_READ);
pixelBufObj_[currentPBO_].maxSize = bufSize;
}
if (useCPU) {
// If converting pixel formats on the CPU we'll always request RGBA8888
// SafeGLReadPixels(0, 0, vfb->fb_stride, vfb->height, UseBGRA8888() ? GL_BGRA_EXT : GL_RGBA, GL_UNSIGNED_BYTE, 0);
} else {
// Otherwise we'll directly request the format we need and let the GPU sort it out
// SafeGLReadPixels(0, 0, vfb->fb_stride, vfb->height, pixelFormat, pixelType, 0);
}
pixelBufObj_[currentPBO_].fb_address = fb_address;
pixelBufObj_[currentPBO_].size = bufSize;
pixelBufObj_[currentPBO_].stride = vfb->fb_stride;
pixelBufObj_[currentPBO_].height = vfb->height;
pixelBufObj_[currentPBO_].format = vfb->format;
pixelBufObj_[currentPBO_].reading = true;
}
currentPBO_ = nextPBO;
}
void FramebufferManagerVulkan::PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h) {
}
void FramebufferManagerVulkan::BeginFrameVulkan() {
BeginFrame();
vulkan2D_.BeginFrame();
FrameData &frame = frameData_[curFrame_];
frame.push_->Reset();
frame.push_->Begin(vulkan_);
if (!useBufferedRendering_) {
// TODO: This hackery should not be necessary. Is it? Need to check.
// We only use a single command buffer in this case.
VkCommandBuffer cmd = vulkan_->GetSurfaceCommandBuffer();
VkRect2D scissor;
scissor.offset = { 0, 0 };
scissor.extent = { (uint32_t)pixelWidth_, (uint32_t)pixelHeight_ };
vkCmdSetScissor(cmd, 0, 1, &scissor);
} else {
// Each render pass will set up scissor again.
}
}
void FramebufferManagerVulkan::EndFrame() {
// We flush to memory last requested framebuffer, if any.
// Only do this in the read-framebuffer modes.
if (updateVRAM_)
PackFramebufferAsync_(nullptr);
FrameData &frame = frameData_[curFrame_];
frame.push_->End();
vulkan2D_.EndFrame();
curFrame_++;
if (curFrame_ >= vulkan_->GetInflightFrames()) {
curFrame_ = 0;
}
}
void FramebufferManagerVulkan::DeviceLost() {
vulkan2D_.DeviceLost();
vulkan2D_->DeviceLost();
DestroyAllFBOs();
DestroyDeviceObjects();
@@ -963,29 +596,10 @@ void FramebufferManagerVulkan::DeviceLost() {
void FramebufferManagerVulkan::DeviceRestore(VulkanContext *vulkan) {
vulkan_ = vulkan;
vulkan2D_.DeviceRestore(vulkan_);
vulkan2D_->DeviceRestore(vulkan_);
InitDeviceObjects();
}
std::vector<FramebufferInfo> FramebufferManagerVulkan::GetFramebufferList() {
std::vector<FramebufferInfo> list;
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *vfb = vfbs_[i];
FramebufferInfo info;
info.fb_address = vfb->fb_address;
info.z_address = vfb->z_address;
info.format = vfb->format;
info.width = vfb->width;
info.height = vfb->height;
info.fbo = vfb->fbo;
list.push_back(info);
}
return list;
}
void FramebufferManagerVulkan::DestroyAllFBOs() {
currentRenderVfb_ = 0;
displayFramebuf_ = 0;
@@ -1006,19 +620,6 @@ void FramebufferManagerVulkan::DestroyAllFBOs() {
bvfbs_.clear();
}
void FramebufferManagerVulkan::FlushBeforeCopy() {
// Flush anything not yet drawn before blitting, downloading, or uploading.
// This might be a stalled list, or unflushed before a block transfer, etc.
// TODO: It's really bad that we are calling SetRenderFramebuffer here with
// all the irrelevant state checking it'll use to decide what to do. Should
// do something more focused here.
SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
if (!draw_->GetNativeObject(Draw::NativeObject::CURRENT_RENDERPASS))
Crash();
drawEngine_->Flush();
}
void FramebufferManagerVulkan::Resized() {
FramebufferManagerCommon::Resized();
@@ -1026,92 +627,3 @@ void FramebufferManagerVulkan::Resized() {
DestroyAllFBOs();
}
}
bool FramebufferManagerVulkan::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxStride) {
// TODO: Doing this synchronously will require stalling the pipeline. Maybe better
// to do it callback-style?
/*
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {
vfb = GetVFBAt(fb_address);
}
if (!vfb) {
// If there's no vfb and we're drawing there, must be memory?
buffer = GPUDebugBuffer(Memory::GetPointer(fb_address | 0x04000000), fb_stride, 512, format);
return true;
}
buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GE_FORMAT_8888, false, true);
if (vfb->fbo)
fbo_bind_for_read(vfb->fbo);
if (gl_extensions.GLES3 || !gl_extensions.IsGLES)
glReadBuffer(GL_COLOR_ATTACHMENT0);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
SafeGLReadPixels(0, 0, vfb->renderWidth, vfb->renderHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer.GetData());
*/
return false;
}
bool FramebufferManagerVulkan::GetOutputFramebuffer(GPUDebugBuffer &buffer) {
// TODO: Doing this synchronously will require stalling the pipeline. Maybe better
// to do it callback-style?
/*
fbo_unbind_read();
int pw = PSP_CoreParameter().pixelWidth;
int ph = PSP_CoreParameter().pixelHeight;
// The backbuffer is flipped.
buffer.Allocate(pw, ph, GPU_DBG_FORMAT_888_RGB, true);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
SafeGLReadPixels(0, 0, pw, ph, GL_RGB, GL_UNSIGNED_BYTE, buffer.GetData());
*/
return false;
}
bool FramebufferManagerVulkan::GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) {
// TODO: Doing this synchronously will require stalling the pipeline. Maybe better
// to do it callback-style?
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {
vfb = GetVFBAt(fb_address);
}
if (!vfb) {
// If there's no vfb and we're drawing there, must be memory?
buffer = GPUDebugBuffer(Memory::GetPointer(z_address | 0x04000000), z_stride, 512, GPU_DBG_FORMAT_16BIT);
return true;
}
/*
buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GPU_DBG_FORMAT_FLOAT, false);
SafeGLReadPixels(0, 0, vfb->renderWidth, vfb->renderHeight, GL_DEPTH_COMPONENT, GL_FLOAT, buffer.GetData());
*/
return false;
}
bool FramebufferManagerVulkan::GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) {
// TODO: Doing this synchronously will require stalling the pipeline. Maybe better
// to do it callback-style?
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {
vfb = GetVFBAt(fb_address);
}
if (!vfb) {
// If there's no vfb and we're drawing there, must be memory?
// TODO: Actually get the stencil.
buffer = GPUDebugBuffer(Memory::GetPointer(fb_address | 0x04000000), fb_stride, 512, GPU_DBG_FORMAT_8888);
return true;
}
/*
buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GPU_DBG_FORMAT_8BIT, false);
SafeGLReadPixels(0, 0, vfb->renderWidth, vfb->renderHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buffer.GetData());
return true;
*/
return false;
}
+16 -54
View File
@@ -22,6 +22,7 @@
#include "GPU/GPUInterface.h"
#include "GPU/Common/GPUDebugInterface.h"
#include "GPU/Vulkan/VulkanUtil.h"
#include "GPU/Vulkan/DepalettizeShaderVulkan.h"
// TODO: Remove?
enum VulkanFBOColorDepth {
@@ -44,19 +45,7 @@ R"( vec2 texelDelta;
vec4 time;
)";
// Simple struct for asynchronous PBO readbacks
// TODO: Probably will need a complete redesign.
struct AsyncPBOVulkan {
// handle;
u32 maxSize;
u32 fb_address;
u32 stride;
u32 height;
u32 size;
GEBufferFormat format;
bool reading;
};
class VulkanPushBuffer;
class FramebufferManagerVulkan : public FramebufferManagerCommon {
public:
@@ -65,9 +54,9 @@ public:
void SetTextureCache(TextureCacheVulkan *tc);
void SetShaderManager(ShaderManagerVulkan *sm);
void SetDrawEngine(DrawEngineVulkan *td) {
drawEngine_ = td;
}
void SetDrawEngine(DrawEngineVulkan *td);
void SetVulkan2D(Vulkan2D *vk2d) { vulkan2D_ = vk2d; }
void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; }
// x,y,w,h are relative to destW, destH which fill out the target completely.
void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) override;
@@ -87,22 +76,8 @@ public:
void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) override;
// For use when texturing from a framebuffer. May create a duplicate if target.
VulkanTexture *GetFramebufferColor(u32 fbRawAddress, VirtualFramebuffer *framebuffer, int flags);
// Reads a rectangular subregion of a framebuffer to the right position in its backing memory.
void ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) override;
void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes) override;
std::vector<FramebufferInfo> GetFramebufferList();
bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override;
bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) override;
bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override;
bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) override;
bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override;
virtual void RebindFramebuffer() override;
VkImageView BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);
@@ -115,7 +90,6 @@ protected:
void BindPostShader(const PostShaderUniforms &uniforms) override;
void SetViewport2D(int x, int y, int w, int h) override;
void DisableState() override {}
void FlushBeforeCopy() override;
// Used by ReadFramebufferToMemory and later framebuffer block copies
void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) override;
@@ -123,16 +97,11 @@ protected:
void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override;
private:
// The returned texture does not need to be free'd, might be returned from a pool (currently single entry)
void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) override;
void DoNotifyDraw();
void UpdatePostShaderUniforms(int bufferWidth, int bufferHeight, int renderWidth, int renderHeight);
void PackFramebufferAsync_(VirtualFramebuffer *vfb);
void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h);
void InitDeviceObjects();
void DestroyDeviceObjects();
@@ -141,31 +110,21 @@ private:
// Used to keep track of command buffers here but have moved all that into Thin3D.
// Used by DrawPixels
VulkanTexture *drawPixelsTex_;
GEBufferFormat drawPixelsTexFormat_;
u8 *convBuf_;
u32 convBufSize_;
VulkanTexture *drawPixelsTex_ = nullptr;
GEBufferFormat drawPixelsTexFormat_ = GE_FORMAT_INVALID;
u8 *convBuf_ = nullptr;
u32 convBufSize_ = 0;
TextureCacheVulkan *textureCacheVulkan_;
ShaderManagerVulkan *shaderManagerVulkan_;
DrawEngineVulkan *drawEngine_;
AsyncPBOVulkan *pixelBufObj_;
int currentPBO_;
DrawEngineVulkan *drawEngineVulkan_;
VulkanPushBuffer *push_;
DepalShaderCacheVulkan depalVulkan_;
enum {
MAX_COMMAND_BUFFERS = 32,
};
// Commandbuffers are handled internally in thin3d, one for each framebuffer pass.
struct FrameData {
VulkanPushBuffer *push_;
};
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES];
int curFrame_;
// This gets copied to the current frame's push buffer as needed.
PostShaderUniforms postUniforms_;
@@ -175,6 +134,9 @@ private:
VkShaderModule fsBasicTex_;
VkShaderModule vsBasicTex_;
VkShaderModule stencilVs_ = VK_NULL_HANDLE;
VkShaderModule stencilFs_ = VK_NULL_HANDLE;
VkPipeline cur2DPipeline_ = VK_NULL_HANDLE;
// Postprocessing
@@ -187,5 +149,5 @@ private:
VkImageView overrideImageView_ = VK_NULL_HANDLE;
// Simple 2D drawing engine.
Vulkan2D vulkan2D_;
Vulkan2D *vulkan2D_;
};
+47 -20
View File
@@ -76,7 +76,9 @@ static const VulkanCommandTableEntry commandTable[] = {
GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
: GPUCommon(gfxCtx, draw),
vulkan_((VulkanContext *)gfxCtx->GetAPIContext()),
drawEngine_(vulkan_, draw) {
drawEngine_(vulkan_, draw),
depalShaderCache_(draw, vulkan_),
vulkan2D_(vulkan_) {
UpdateVsyncInterval(true);
CheckGPUFeatures();
@@ -97,10 +99,14 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
framebufferManagerVulkan_->SetTextureCache(textureCacheVulkan_);
framebufferManagerVulkan_->SetDrawEngine(&drawEngine_);
framebufferManagerVulkan_->SetShaderManager(shaderManagerVulkan_);
textureCacheVulkan_->SetFramebufferManager(framebufferManagerVulkan_);
framebufferManagerVulkan_->SetVulkan2D(&vulkan2D_);
textureCacheVulkan_->SetDepalShaderCache(&depalShaderCache_);
textureCacheVulkan_->SetFramebufferManager(framebufferManagerVulkan_);
textureCacheVulkan_->SetShaderManager(shaderManagerVulkan_);
textureCacheVulkan_->SetDrawEngine(&drawEngine_);
textureCacheVulkan_->SetVulkan2D(&vulkan2D_);
InitDeviceObjects();
// Sanity check gstate
if ((int *)&gstate.transferstart - (int *)&gstate != 0xEA) {
@@ -155,7 +161,9 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
}
GPU_Vulkan::~GPU_Vulkan() {
DestroyDeviceObjects();
framebufferManagerVulkan_->DestroyAllFBOs();
vulkan2D_.Shutdown();
depalShaderCache_.Clear();
delete textureCacheVulkan_;
delete pipelineManager_;
@@ -209,9 +217,19 @@ void GPU_Vulkan::BeginHostFrame() {
resized_ = false;
textureCacheVulkan_->StartFrame();
depalShaderCache_.Decimate();
int curFrame = vulkan_->GetCurFrame();
FrameData &frame = frameData_[curFrame];
frame.push_->Reset();
frame.push_->Begin(vulkan_);
framebufferManagerVulkan_->BeginFrameVulkan();
framebufferManagerVulkan_->SetPushBuffer(frameData_[curFrame].push_);
depalShaderCache_.SetPushBuffer(frameData_[curFrame].push_);
textureCacheVulkan_->SetPushBuffer(frameData_[curFrame].push_);
vulkan2D_.BeginFrame();
shaderManagerVulkan_->DirtyShader();
gstate_c.Dirty(DIRTY_ALL);
@@ -226,6 +244,12 @@ void GPU_Vulkan::BeginHostFrame() {
}
void GPU_Vulkan::EndHostFrame() {
int curFrame = vulkan_->GetCurFrame();
FrameData &frame = frameData_[curFrame];
frame.push_->End();
vulkan2D_.EndFrame();
drawEngine_.EndFrame();
framebufferManagerVulkan_->EndFrame();
textureCacheVulkan_->EndFrame();
@@ -600,7 +624,6 @@ void GPU_Vulkan::Execute_Bezier(u32 op, u32 diff) {
int bz_vcount = (op >> 8) & 0xFF;
bool computeNormals = gstate.isLightingEnabled();
bool patchFacing = gstate.patchfacing & 1;
int bytesRead = 0;
if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
@@ -611,6 +634,7 @@ void GPU_Vulkan::Execute_Bezier(u32 op, u32 diff) {
}
}
int bytesRead = 0;
UpdateUVScaleOffset();
drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead);
@@ -769,7 +793,26 @@ void GPU_Vulkan::FastLoadBoneMatrix(u32 target) {
gstate.FastLoadBoneMatrix(target);
}
void GPU_Vulkan::InitDeviceObjects() {
// Initialize framedata
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
frameData_[i].push_ = new VulkanPushBuffer(vulkan_, 64 * 1024);
}
}
void GPU_Vulkan::DestroyDeviceObjects() {
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
if (frameData_[i].push_) {
frameData_[i].push_->Destroy(vulkan_);
delete frameData_[i].push_;
frameData_[i].push_ = nullptr;
}
}
}
void GPU_Vulkan::DeviceLost() {
DestroyDeviceObjects();
framebufferManagerVulkan_->DeviceLost();
drawEngine_.DeviceLost();
pipelineManager_->DeviceLost();
@@ -839,10 +882,6 @@ void GPU_Vulkan::ClearShaderCache() {
// TODO
}
std::vector<FramebufferInfo> GPU_Vulkan::GetFramebufferList() {
return framebufferManagerVulkan_->GetFramebufferList();
}
void GPU_Vulkan::DoState(PointerWrap &p) {
GPUCommon::DoState(p);
@@ -860,18 +899,6 @@ void GPU_Vulkan::DoState(PointerWrap &p) {
}
}
bool GPU_Vulkan::GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) {
return drawEngine_.GetCurrentSimpleVertices(count, vertices, indices);
}
bool GPU_Vulkan::DescribeCodePtr(const u8 *ptr, std::string &name) {
if (drawEngine_.IsCodePtrVertexDecoder(ptr)) {
name = "VertexDecoderJit";
return true;
}
return false;
}
std::vector<std::string> GPU_Vulkan::DebugGetShaderIDs(DebugShaderType type) {
if (type == SHADER_TYPE_VERTEXLOADER) {
return drawEngine_.DebugGetVertexLoaderIDs();
+13 -3
View File
@@ -84,9 +84,6 @@ public:
// Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend.
std::vector<std::string> DebugGetShaderIDs(DebugShaderType shader) override;
std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override;
std::vector<FramebufferInfo> GetFramebufferList() override;
bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) override;
bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
protected:
void FastRunLoop(DisplayList &list) override;
@@ -104,6 +101,10 @@ private:
void ReinitializeInternal() override;
inline void UpdateVsyncInterval(bool force);
void UpdateCmdInfo();
void InitDeviceObjects();
void DestroyDeviceObjects();
static CommandInfo cmdInfo_[256];
VulkanContext *vulkan_;
@@ -124,4 +125,13 @@ private:
std::string reportingPrimaryInfo_;
std::string reportingFullInfo_;
// Simple 2D drawing engine.
Vulkan2D vulkan2D_;
struct FrameData {
VulkanPushBuffer *push_;
};
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES]{};
};
+4
View File
@@ -122,6 +122,8 @@ static bool UsesBlendConstant(int factor) {
static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pipelineCache,
VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &key,
const VertexDecoder *vtxDec, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) {
bool useBlendConstant = false;
VkPipelineColorBlendAttachmentState blend0 = {};
blend0.blendEnable = key.blendEnable;
if (key.blendEnable) {
@@ -166,6 +168,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
if (key.blendEnable &&
(UsesBlendConstant(key.srcAlpha) || UsesBlendConstant(key.srcColor) || UsesBlendConstant(key.destAlpha) || UsesBlendConstant(key.destColor))) {
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_BLEND_CONSTANTS;
useBlendConstant = true;
}
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_SCISSOR;
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_VIEWPORT;
@@ -285,6 +288,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
VulkanPipeline *vulkanPipeline = new VulkanPipeline();
vulkanPipeline->pipeline = pipeline;
vulkanPipeline->uniformBlocks = UB_VS_FS_BASE;
vulkanPipeline->useBlendConstant = useBlendConstant;
if (useHwTransform) {
if (vs->HasLights()) {
vulkanPipeline->uniformBlocks |= UB_VS_LIGHTS;
+1
View File
@@ -64,6 +64,7 @@ enum {
struct VulkanPipeline {
VkPipeline pipeline;
int uniformBlocks; // UB_ enum above.
bool useBlendConstant;
};
class VulkanContext;
+13 -26
View File
@@ -16,6 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Common/Vulkan/VulkanLoader.h"
#include "thin3d/VulkanRenderManager.h"
#include "math/dataconv.h"
#include "GPU/Math3D.h"
@@ -25,14 +26,12 @@
#include "Core/System.h"
#include "Core/Config.h"
#include "Core/Reporting.h"
//#include "GPU/Vulkan/StateMappingVulkan.h"
#include "GPU/Vulkan/GPU_Vulkan.h"
#include "GPU/Vulkan/PipelineManagerVulkan.h"
#include "GPU/Vulkan/TextureCacheVulkan.h"
#include "GPU/Vulkan/FramebufferVulkan.h"
#include "GPU/Vulkan/ShaderManagerVulkan.h"
#include "GPU/Vulkan/DrawEngineVulkan.h"
//#include "GPU/Vulkan/PixelShaderGeneratorVulkan.h"
// These tables all fit into u8s.
static const VkBlendFactor vkBlendFactorLookup[(size_t)BlendFactor::COUNT] = {
@@ -122,8 +121,8 @@ static const VkLogicOp logicOps[] = {
VK_LOGIC_OP_SET,
};
void ResetShaderBlending() {
//
void DrawEngineVulkan::ResetShaderBlending() {
boundSecondary_ = VK_NULL_HANDLE;
}
// TODO: Do this more progressively. No need to compute the entire state if the entire state hasn't changed.
@@ -135,8 +134,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag
bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE;
if (gstate_c.IsDirty(DIRTY_BLEND_STATE)) {
// Unfortunately, this isn't implemented yet.
gstate_c.SetAllowShaderBlend(false);
gstate_c.SetAllowShaderBlend(!g_Config.bDisableSlowFramebufEffects);
if (gstate.isModeClear()) {
key.logicOpEnable = false;
key.logicOp = VK_LOGIC_OP_CLEAR;
@@ -369,42 +367,31 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag
}
}
void DrawEngineVulkan::ApplyDrawStateLate(VkCommandBuffer cmd, bool applyStencilRef, uint8_t stencilRef) {
void DrawEngineVulkan::ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant) {
// At this point, we know if the vertices are full alpha or not.
// TODO: Set the nearest/linear here (since we correctly know if alpha/color tests are needed)?
if (!gstate.isModeClear()) {
// TODO: Test texture?
/*
if (fboTexNeedBind_) {
// Note that this is positions, not UVs, that we need the copy from.
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY);
// If we are rendering at a higher resolution, linear is probably best for the dest color.
boundSecondary_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE1_IMAGEVIEW);
fboTexBound_ = true;
fboTexNeedBind_ = false;
}
*/
}
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
vkCmdSetScissor(cmd, 0, 1, &dynState_.scissor);
vkCmdSetViewport(cmd, 0, 1, &dynState_.viewport);
renderManager->SetScissor(dynState_.scissor);
renderManager->SetViewport(dynState_.viewport);
}
if (gstate_c.IsDirty(DIRTY_DEPTHSTENCIL_STATE)) {
if (dynState_.useStencil) {
vkCmdSetStencilWriteMask(cmd, VK_STENCIL_FRONT_AND_BACK, dynState_.stencilWriteMask);
vkCmdSetStencilCompareMask(cmd, VK_STENCIL_FRONT_AND_BACK, dynState_.stencilCompareMask);
if (!applyStencilRef) {
vkCmdSetStencilReference(cmd, VK_STENCIL_FRONT_AND_BACK, dynState_.stencilRef);
}
}
if ((gstate_c.IsDirty(DIRTY_DEPTHSTENCIL_STATE) && dynState_.useStencil) || applyStencilRef) {
renderManager->SetStencilParams(dynState_.stencilWriteMask, dynState_.stencilCompareMask, applyStencilRef ? stencilRef : dynState_.stencilRef);
}
if (applyStencilRef) {
vkCmdSetStencilReference(cmd, VK_STENCIL_FRONT_AND_BACK, stencilRef);
}
if (gstate_c.IsDirty(DIRTY_BLEND_STATE)) {
if (gstate_c.IsDirty(DIRTY_BLEND_STATE) && useBlendConstant) {
float bc[4];
Uint8x4ToFloat4(bc, dynState_.blendColor);
vkCmdSetBlendConstants(cmd, bc);
renderManager->SetBlendFactor(bc);
}
}
}
+1 -4
View File
@@ -57,7 +57,4 @@ struct VulkanPipelineRasterStateKey {
size_t size = sizeof(VulkanPipelineRasterStateKey);
return memcmp(this, &other, size) < 0;
}
};
class ShaderManagerVulkan;
void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerVulkan *shaderManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &dynState);
};
+187
View File
@@ -0,0 +1,187 @@
// Copyright (c) 2014- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "base/logging.h"
#include "ext/native/thin3d/thin3d.h"
#include "ext/native/thin3d/VulkanRenderManager.h"
#include "Core/Reporting.h"
#include "GPU/Common/StencilCommon.h"
#include "GPU/Vulkan/FramebufferVulkan.h"
#include "GPU/Vulkan/FragmentShaderGeneratorVulkan.h"
#include "GPU/Vulkan/ShaderManagerVulkan.h"
#include "GPU/Vulkan/TextureCacheVulkan.h"
#include "GPU/Vulkan/VulkanUtil.h"
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
struct StencilValueUB {
uint32_t u_stencilValue[4];
};
static const char *stencil_fs = R"(#version 400
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (binding = 0) uniform sampler2D tex;
layout(push_constant) uniform params {
int u_stencilValue;
};
layout (location = 0) in vec2 v_texcoord0;
layout (location = 0) out vec4 fragColor0;
void main() {
vec4 index = texture(tex, v_texcoord0);
int indexBits = int(floor(index.a * 255.99)) & 0xFF;
if ((indexBits & u_stencilValue) == 0)
discard;
fragColor0 = index.aaaa;
}
)";
static const char stencil_vs[] = R"(#version 400
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (location = 0) out vec2 v_texcoord0;
out gl_PerVertex { vec4 gl_Position; };
void main() {
int id = gl_VertexIndex;
v_texcoord0.x = (id == 2) ? 2.0 : 0.0;
v_texcoord0.y = (id == 1) ? 2.0 : 0.0;
gl_Position = vec4(v_texcoord0 * vec2(2.0, 2.0) + vec2(-1.0, -1.0), 0.0, 1.0);
}
)";
// In Vulkan we should be able to simply copy the stencil data directly to a stencil buffer without
// messing about with bitplane textures and the like. Or actually, maybe not... Let's start with
// the traditional approach.
bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skipZero) {
if (!MayIntersectFramebuffer(addr)) {
return false;
}
VirtualFramebuffer *dstBuffer = 0;
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *vfb = vfbs_[i];
if (MaskedEqual(vfb->fb_address, addr)) {
dstBuffer = vfb;
}
}
if (!dstBuffer) {
return false;
}
int values = 0;
u8 usedBits = 0;
const u8 *src = Memory::GetPointer(addr);
if (!src) {
return false;
}
switch (dstBuffer->format) {
case GE_FORMAT_565:
// Well, this doesn't make much sense.
return false;
case GE_FORMAT_5551:
usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight);
values = 2;
break;
case GE_FORMAT_4444:
usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight);
values = 16;
break;
case GE_FORMAT_8888:
usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight);
values = 256;
break;
case GE_FORMAT_INVALID:
// Impossible.
break;
}
std::string error;
if (!stencilVs_) {
stencilVs_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_VERTEX_BIT, stencil_vs, &error);
stencilFs_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_FRAGMENT_BIT, stencil_fs, &error);
}
VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::FRAMEBUFFER_RENDERPASS);
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
if (usedBits == 0) {
if (skipZero) {
// Common when creating buffers, it's already 0. We're done.
return false;
}
// TODO: Find a nice way to clear alpha here too.
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::CLEAR });
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
return true;
}
shaderManagerVulkan_->DirtyLastShader();
textureCacheVulkan_->ForgetLastTexture();
u16 w = dstBuffer->renderWidth;
u16 h = dstBuffer->renderHeight;
float u1 = 1.0f;
float v1 = 1.0f;
MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight, u1, v1);
if (dstBuffer->fbo) {
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::CLEAR });
} else {
// something is wrong...
}
VkPipeline pipeline = vulkan2D_->GetPipeline(rp, stencilVs_, stencilFs_, false, Vulkan2D::VK2DDepthStencilMode::STENCIL_REPLACE_ALWAYS);
renderManager->BindPipeline(pipeline);
renderManager->SetViewport({ 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f });
renderManager->SetScissor({ { 0, 0, },{ (uint32_t)w, (uint32_t)h } });
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE);
VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(overrideImageView_, nearestSampler_, VK_NULL_HANDLE, VK_NULL_HANDLE);
for (int i = 1; i < values; i += i) {
if (!(usedBits & i)) {
// It's already zero, let's skip it.
continue;
}
// These feel a little backwards : Mask is the bits that are going to be written, while value
// is the "mask" that will be tested against.
uint8_t mask = 0;
uint32_t value = 0;
if (dstBuffer->format == GE_FORMAT_4444) {
mask = i | (i << 4);
value = i * 16;
} else if (dstBuffer->format == GE_FORMAT_5551) {
mask = 0xFF;
value = i * 128;
} else {
mask = i;
value = i;
}
renderManager->SetStencilParams(mask, 0xFF, 0xFF);
renderManager->PushConstants(vulkan2D_->GetPipelineLayout(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4, &value);
renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, VK_NULL_HANDLE, 0, 3); // full screen triangle
}
overrideImageView_ = VK_NULL_HANDLE;
RebindFramebuffer();
return true;
}
+89 -57
View File
@@ -23,6 +23,8 @@
#include "math/math_util.h"
#include "profiler/profiler.h"
#include "thin3d/thin3d.h"
#include "thin3d/VulkanRenderManager.h"
#include "Common/ColorConv.h"
#include "Core/Config.h"
#include "Core/Host.h"
@@ -130,10 +132,19 @@ TextureCacheVulkan::TextureCacheVulkan(Draw::DrawContext *draw, VulkanContext *v
lastBoundTexture = nullptr;
allocator_ = new VulkanDeviceAllocator(vulkan_, TEXCACHE_MIN_SLAB_SIZE, TEXCACHE_MAX_SLAB_SIZE);
VkSamplerCreateInfo samp{ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
samp.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samp.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samp.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samp.magFilter = VK_FILTER_NEAREST;
samp.minFilter = VK_FILTER_NEAREST;
samp.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
vkCreateSampler(vulkan_->GetDevice(), &samp, nullptr, &samplerNearest_);
SetupTextureDecoder();
}
TextureCacheVulkan::~TextureCacheVulkan() {
vulkan_->Delete().QueueDeleteSampler(samplerNearest_);
Clear(true);
if (allocator_) {
@@ -152,6 +163,11 @@ void TextureCacheVulkan::SetFramebufferManager(FramebufferManagerVulkan *fbManag
framebufferManager_ = fbManager;
}
void TextureCacheVulkan::SetVulkan2D(Vulkan2D *vk2d) {
vulkan2D_ = vk2d;
depalShaderCache_->SetVulkan2D(vk2d);
}
void TextureCacheVulkan::DeviceLost() {
Clear(true);
@@ -274,6 +290,8 @@ void TextureCacheVulkan::SetFramebufferSamplingParams(u16 bufferWidth, u16 buffe
void TextureCacheVulkan::StartFrame() {
InvalidateLastTexture();
depalShaderCache_->Decimate();
timesInvalidatedAllThisFrame_ = 0;
texelsScaledThisFrame_ = 0;
@@ -331,61 +349,42 @@ void TextureCacheVulkan::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutB
void TextureCacheVulkan::BindTexture(TexCacheEntry *entry) {
if (!entry || !entry->vkTex) {
imageView_ = VK_NULL_HANDLE;
sampler_ = VK_NULL_HANDLE;
curSampler_ = VK_NULL_HANDLE;
return;
}
imageView_ = entry->vkTex->texture_->GetImageView();
SamplerCacheKey key;
UpdateSamplingParams(*entry, key);
sampler_ = samplerCache_.GetOrCreateSampler(key);
curSampler_ = samplerCache_.GetOrCreateSampler(key);
}
void TextureCacheVulkan::Unbind() {
imageView_ = VK_NULL_HANDLE;
sampler_ = VK_NULL_HANDLE;
curSampler_ = VK_NULL_HANDLE;
InvalidateLastTexture();
}
void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) {
DepalShaderVulkan *depal = nullptr;
DepalShaderVulkan *depalShader = nullptr;
const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat();
if ((entry->status & TexCacheEntry::STATUS_DEPALETTIZE) && !g_Config.bDisableSlowFramebufEffects) {
// depal = depalShaderCache_->GetDepalettizeShader(clutFormat, framebuffer->drawnFormat);
depalShader = depalShaderCache_->GetDepalettizeShader(clutFormat, framebuffer->drawnFormat);
}
if (depal) {
// VulkanTexture *clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_);
// VulkanFBO *depalFBO = framebufferManager_->GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, VK_FBO_8888);
if (depalShader) {
depalShaderCache_->SetPushBuffer(drawEngine_->GetPushBufferForTextureData());
VulkanTexture *clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_);
//depalFBO->BeginPass(cmd);
Draw::Framebuffer *depalFBO = framebufferManager_->GetTempFBO(
framebuffer->renderWidth, framebuffer->renderHeight, Draw::FBO_8888);
draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE });
struct Pos {
Pos(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {
}
float x;
float y;
float z;
Vulkan2D::Vertex verts[4] = {
{ -1, -1, 0.0f, 0, 0 },
{ 1, -1, 0.0f, 1, 0 },
{ -1, 1, 0.0f, 0, 1 },
{ 1, 1, 0.0f, 1, 1 },
};
struct UV {
UV(float u_, float v_) : u(u_), v(v_) {
}
float u;
float v;
};
Pos pos[4] = {
{ -1, -1, -1 },
{ 1, -1, -1 },
{ 1, 1, -1 },
{ -1, 1, -1 },
};
UV uv[4] = {
{ 0, 0 },
{ 1, 0 },
{ 1, 1 },
{ 0, 1 },
};
static const int indices[4] = { 0, 1, 3, 2 };
// If min is not < max, then we don't have values (wasn't set during decode.)
if (gstate_c.vertBounds.minV < gstate_c.vertBounds.maxV) {
@@ -405,27 +404,43 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr
const float top = v1 * invHalfHeight - 1.0f;
const float bottom = v2 * invHalfHeight - 1.0f;
// Points are: BL, BR, TR, TL.
pos[0] = Pos(left, bottom, -1.0f);
pos[1] = Pos(right, bottom, -1.0f);
pos[2] = Pos(right, top, -1.0f);
pos[3] = Pos(left, top, -1.0f);
verts[0].x = left;
verts[0].y = bottom;
verts[1].x = right;
verts[1].y = bottom;
verts[2].x = left;
verts[2].y = top;
verts[3].x = right;
verts[3].y = top;
// And also the UVs, same order.
const float uvleft = u1 * invWidth;
const float uvright = u2 * invWidth;
const float uvtop = v1 * invHeight;
const float uvbottom = v2 * invHeight;
uv[0] = UV(uvleft, uvbottom);
uv[1] = UV(uvright, uvbottom);
uv[2] = UV(uvright, uvtop);
uv[3] = UV(uvleft, uvtop);
verts[0].u = uvleft;
verts[0].v = uvbottom;
verts[1].u = uvright;
verts[1].v = uvbottom;
verts[2].u = uvleft;
verts[2].v = uvtop;
verts[3].u = uvright;
verts[3].v = uvtop;
}
shaderManagerVulkan_->DirtyLastShader();
VkBuffer pushed;
uint32_t offset = push_->PushAligned(verts, sizeof(verts), 4, &pushed);
//depalFBO->EndPass(cmd);
//depalFBO->TransitionToTexture(cmd);
//imageView = depalFBO->GetColorImageView();
draw_->BindFramebufferAsTexture(framebuffer->fbo, 0, Draw::FB_COLOR_BIT, 0);
VkImageView fbo = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW);
VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(fbo, samplerNearest_, clutTexture->GetImageView(), samplerNearest_);
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
renderManager->BindPipeline(depalShader->pipeline);
renderManager->SetScissor(VkRect2D{ {0, 0}, { framebuffer->renderWidth, framebuffer->renderHeight} });
renderManager->SetViewport(VkViewport{ 0.f, 0.f, (float)framebuffer->renderWidth, (float)framebuffer->renderHeight, 0.f, 1.f });
renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, pushed, offset, 4);
shaderManagerVulkan_->DirtyLastShader();
const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16);
const u32 clutTotalColors = clutMaxBytes_ / bytesPerColor;
@@ -434,10 +449,16 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr
gstate_c.SetTextureFullAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL);
gstate_c.SetTextureSimpleAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_SIMPLE);
// imageView_ = depalFbo->getImageView().
framebufferManager_->RebindFramebuffer();
draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, 0);
imageView_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW);
// Need to rebind the pipeline since we switched it.
drawEngine_->DirtyPipeline();
} else {
entry->status &= ~TexCacheEntry::STATUS_DEPALETTIZE;
framebufferManager_->RebindFramebuffer();
imageView_ = framebufferManagerVulkan_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET);
gstate_c.SetTextureFullAlpha(gstate.getTextureFormat() == GE_TFMT_5650);
@@ -446,7 +467,7 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr
SamplerCacheKey samplerKey;
SetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight, samplerKey);
sampler_ = samplerCache_.GetOrCreateSampler(samplerKey);
curSampler_ = samplerCache_.GetOrCreateSampler(samplerKey);
InvalidateLastTexture(entry);
}
@@ -471,6 +492,7 @@ VkFormat ToVulkanFormat(ReplacedTextureFormat fmt) {
void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceImages) {
entry->status &= ~TexCacheEntry::STATUS_ALPHA_MASK;
VkCommandBuffer cmdInit = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
// For the estimate, we assume cluts always point to 8888 for simplicity.
cacheSizeEstimate_ += EstimateTexMemoryUsage(entry);
@@ -533,6 +555,11 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm
int h = gstate.getTextureHeight(0);
ReplacedTexture &replaced = replacer_.FindReplacement(cachekey, entry->fullhash, w, h);
if (replaced.GetSize(0, w, h)) {
if (replaceImages) {
// Since we're replacing the texture, we can't replace the image inside.
ReleaseTexture(entry, true);
replaceImages = false;
}
// We're replacing, so we won't scale.
scaleFactor = 1;
entry->status |= TexCacheEntry::STATUS_IS_SCALED;
@@ -569,7 +596,9 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm
if (replaced.Valid()) {
actualFmt = ToVulkanFormat(replaced.Format(0));
}
if (!entry->vkTex) {
{
delete entry->vkTex;
entry->vkTex = new CachedTextureVulkan();
entry->vkTex->texture_ = new VulkanTexture(vulkan_, allocator_);
VulkanTexture *image = entry->vkTex->texture_;
@@ -593,7 +622,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm
break;
}
bool allocSuccess = image->CreateDirect(w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping);
bool allocSuccess = image->CreateDirect(cmdInit, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping);
if (!allocSuccess && !lowMemoryMode_) {
WARN_LOG_REPORT(G3D, "Texture cache ran out of GPU memory; switching to low memory mode");
lowMemoryMode_ = true;
@@ -612,15 +641,13 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm
scaleFactor = 1;
actualFmt = dstFmt;
allocSuccess = image->CreateDirect(w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping);
allocSuccess = image->CreateDirect(cmdInit, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping);
}
if (!allocSuccess) {
delete entry->vkTex;
entry->vkTex = nullptr;
}
} else {
entry->vkTex->texture_->TransitionForUpload();
}
lastBoundTexture = entry->vkTex;
@@ -657,7 +684,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm
} else {
if (fakeMipmap) {
LoadTextureLevel(*entry, (uint8_t *)data, stride, level, scaleFactor, dstFmt);
entry->vkTex->texture_->UploadMip(0, mipWidth, mipHeight, texBuf, bufferOffset, stride / bpp);
entry->vkTex->texture_->UploadMip(cmdInit, 0, mipWidth, mipHeight, texBuf, bufferOffset, stride / bpp);
break;
} else {
LoadTextureLevel(*entry, (uint8_t *)data, stride, i, scaleFactor, dstFmt);
@@ -666,7 +693,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm
replacer_.NotifyTextureDecoded(replacedInfo, data, stride, i, mipWidth, mipHeight);
}
}
entry->vkTex->texture_->UploadMip(i, mipWidth, mipHeight, texBuf, bufferOffset, stride / bpp);
entry->vkTex->texture_->UploadMip(cmdInit, i, mipWidth, mipHeight, texBuf, bufferOffset, stride / bpp);
}
if (maxLevel == 0) {
@@ -679,7 +706,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm
}
}
entry->vkTex->texture_->EndCreate();
entry->vkTex->texture_->EndCreate(cmdInit);
gstate_c.SetTextureFullAlpha(entry->GetAlphaStatus() == TexCacheEntry::STATUS_ALPHA_FULL);
gstate_c.SetTextureSimpleAlpha(entry->GetAlphaStatus() != TexCacheEntry::STATUS_ALPHA_UNKNOWN);
@@ -783,3 +810,8 @@ void TextureCacheVulkan::LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePt
}
}
}
bool TextureCacheVulkan::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) {
// TODO
return false;
}
+13 -2
View File
@@ -61,6 +61,7 @@ private:
DenseHashMap<SamplerCacheKey, VkSampler, (VkSampler)VK_NULL_HANDLE> cache_;
};
class Vulkan2D;
class TextureCacheVulkan : public TextureCacheCommon {
public:
@@ -83,6 +84,10 @@ public:
void SetDrawEngine(DrawEngineVulkan *td) {
drawEngine_ = td;
}
void SetVulkan2D(Vulkan2D *vk2d);
void SetPushBuffer(VulkanPushBuffer *push) {
push_ = push;
}
void ForgetLastTexture() override {
lastBoundTexture = nullptr;
@@ -96,10 +101,12 @@ public:
void GetVulkanHandles(VkImageView &imageView, VkSampler &sampler) {
imageView = imageView_;
sampler = sampler_;
sampler = curSampler_;
}
void SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight, SamplerCacheKey &key);
bool GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) override;
protected:
void BindTexture(TexCacheEntry *entry) override;
void Unbind() override;
@@ -117,6 +124,7 @@ private:
VulkanContext *vulkan_;
VulkanDeviceAllocator *allocator_;
VulkanPushBuffer *push_;
SamplerCache samplerCache_;
@@ -132,10 +140,13 @@ private:
DepalShaderCacheVulkan *depalShaderCache_;
ShaderManagerVulkan *shaderManagerVulkan_;
DrawEngineVulkan *drawEngine_;
Vulkan2D *vulkan2D_;
// Bound state to emulate an API similar to the others
VkImageView imageView_ = VK_NULL_HANDLE;
VkSampler sampler_ = VK_NULL_HANDLE;
VkSampler curSampler_ = VK_NULL_HANDLE;
VkSampler samplerNearest_ = VK_NULL_HANDLE;
};
VkFormat getClutDestFormatVulkan(GEPaletteFormat format);
+1 -1
View File
@@ -636,7 +636,7 @@ bool GenerateVulkanGLSLVertexShader(const ShaderID &id, char *buffer, bool *uses
if (doBezier || doSpline)
WRITE(p, " v_texcoord = vec3(tex.xy * base.uvscaleoffset.xy + base.uvscaleoffset.zw, 0.0);\n");
else
WRITE(p, " v_texcoord = vec3(texcoord.xy, 0.0);\n");
WRITE(p, " v_texcoord = vec3(texcoord.xy * base.uvscaleoffset.xy, 0.0);\n");
} else {
WRITE(p, " v_texcoord = vec3(0.0);\n");
}
+46 -51
View File
@@ -20,34 +20,7 @@
#include "Common/Vulkan/VulkanContext.h"
#include "GPU/Vulkan/VulkanUtil.h"
VulkanFBO::VulkanFBO() : color_(nullptr), depthStencil_(nullptr) {}
VulkanFBO::~VulkanFBO() {
delete color_;
delete depthStencil_;
}
void VulkanFBO::Create(VulkanContext *vulkan, VkRenderPass rp_compatible, int width, int height, VkFormat color_Format) {
color_ = new VulkanTexture(vulkan);
VkImageCreateFlags flags = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
color_->CreateDirect(width, height, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, flags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, nullptr);
depthStencil_->CreateDirect(width, height, 1, VK_FORMAT_D24_UNORM_S8_UINT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, flags | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, nullptr);
VkImageView views[2] = { color_->GetImageView(), depthStencil_->GetImageView() };
VkFramebufferCreateInfo fb = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
fb.pAttachments = views;
fb.attachmentCount = 2;
fb.flags = 0;
fb.renderPass = rp_compatible;
fb.width = width;
fb.height = height;
fb.layers = 1;
vkCreateFramebuffer(vulkan->GetDevice(), &fb, nullptr, &framebuffer_);
}
Vulkan2D::Vulkan2D(VulkanContext *vulkan) : vulkan_(vulkan), curFrame_(0) {
Vulkan2D::Vulkan2D(VulkanContext *vulkan) : vulkan_(vulkan) {
InitDeviceObjects();
}
@@ -63,6 +36,7 @@ void Vulkan2D::DestroyDeviceObjects() {
for (int i = 0; i < vulkan_->GetInflightFrames(); i++) {
if (frameData_[i].descPool != VK_NULL_HANDLE) {
vulkan_->Delete().QueueDeleteDescriptorPool(frameData_[i].descPool);
frameData_[i].descPool = VK_NULL_HANDLE;
}
}
for (auto it : pipelines_) {
@@ -79,9 +53,16 @@ void Vulkan2D::DestroyDeviceObjects() {
vkDestroyPipelineLayout(device, pipelineLayout_, nullptr);
pipelineLayout_ = VK_NULL_HANDLE;
}
// pipelineBasicTex_ and pipelineBasicTex_ come from vulkan2D_.
if (pipelineCache_ != VK_NULL_HANDLE) {
vulkan_->Delete().QueueDeletePipelineCache(pipelineCache_);
pipelineCache_ = VK_NULL_HANDLE;
}
}
void Vulkan2D::InitDeviceObjects() {
pipelineCache_ = vulkan_->CreatePipelineCache();
// All resources we need for PSP drawing. Usually only bindings 0 and 2-4 are populated.
VkDescriptorSetLayoutBinding bindings[2] = {};
bindings[0].descriptorCount = 1;
@@ -102,12 +83,12 @@ void Vulkan2D::InitDeviceObjects() {
assert(VK_SUCCESS == res);
VkDescriptorPoolSize dpTypes[1];
dpTypes[0].descriptorCount = 1500;
dpTypes[0].descriptorCount = 3000;
dpTypes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
VkDescriptorPoolCreateInfo dp = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
dp.flags = 0; // Don't want to mess around with individually freeing these, let's go fixed each frame and zap the whole array. Might try the dynamic approach later.
dp.maxSets = 1500;
dp.maxSets = 3000;
dp.pPoolSizes = dpTypes;
dp.poolSizeCount = ARRAY_SIZE(dpTypes);
for (int i = 0; i < ARRAY_SIZE(frameData_); i++) {
@@ -117,7 +98,7 @@ void Vulkan2D::InitDeviceObjects() {
VkPushConstantRange push = {};
push.offset = 0;
push.size = 32;
push.size = 16;
push.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
@@ -140,15 +121,13 @@ void Vulkan2D::DeviceRestore(VulkanContext *vulkan) {
}
void Vulkan2D::BeginFrame() {
FrameData &frame = frameData_[curFrame_];
int curFrame = vulkan_->GetCurFrame();
FrameData &frame = frameData_[curFrame];
frame.descSets.clear();
vkResetDescriptorPool(vulkan_->GetDevice(), frame.descPool, 0);
}
void Vulkan2D::EndFrame() {
curFrame_++;
if (curFrame_ >= vulkan_->GetInflightFrames())
curFrame_ = 0;
}
VkDescriptorSet Vulkan2D::GetDescriptorSet(VkImageView tex1, VkSampler sampler1, VkImageView tex2, VkSampler sampler2) {
@@ -158,7 +137,8 @@ VkDescriptorSet Vulkan2D::GetDescriptorSet(VkImageView tex1, VkSampler sampler1,
key.sampler[0] = sampler1;
key.sampler[1] = sampler2;
FrameData *frame = &frameData_[curFrame_];
int curFrame = vulkan_->GetCurFrame();
FrameData *frame = &frameData_[curFrame];
auto iter = frame->descSets.find(key);
if (iter != frame->descSets.end()) {
return iter->second;
@@ -215,11 +195,13 @@ VkDescriptorSet Vulkan2D::GetDescriptorSet(VkImageView tex1, VkSampler sampler1,
return desc;
}
VkPipeline Vulkan2D::GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShaderModule vs, VkShaderModule fs) {
VkPipeline Vulkan2D::GetPipeline(VkRenderPass rp, VkShaderModule vs, VkShaderModule fs, bool readVertices, VK2DDepthStencilMode depthStencilMode) {
PipelineKey key;
key.vs = vs;
key.fs = fs;
key.rp = rp;
key.depthStencilMode = depthStencilMode;
key.readVertices = readVertices;
auto iter = pipelines_.find(key);
if (iter != pipelines_.end()) {
@@ -228,7 +210,7 @@ VkPipeline Vulkan2D::GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShade
VkPipelineColorBlendAttachmentState blend0 = {};
blend0.blendEnable = false;
blend0.colorWriteMask = 0xF;
blend0.colorWriteMask = depthStencilMode == VK2DDepthStencilMode::STENCIL_REPLACE_ALWAYS ? 0 : 0xF;
VkPipelineColorBlendStateCreateInfo cbs = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
cbs.pAttachments = &blend0;
@@ -237,13 +219,32 @@ VkPipeline Vulkan2D::GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShade
VkPipelineDepthStencilStateCreateInfo dss = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
dss.depthBoundsTestEnable = false;
dss.stencilTestEnable = false;
dss.depthTestEnable = false;
dss.stencilTestEnable = false;
switch (depthStencilMode) {
case VK2DDepthStencilMode::NONE:
break;
case VK2DDepthStencilMode::STENCIL_REPLACE_ALWAYS:
dss.stencilTestEnable = true;
dss.front.reference = 0xFF;
dss.front.compareMask = 0xFF;
dss.front.compareOp = VK_COMPARE_OP_ALWAYS;
dss.front.depthFailOp = VK_STENCIL_OP_REPLACE;
dss.front.failOp = VK_STENCIL_OP_REPLACE;
dss.front.passOp = VK_STENCIL_OP_REPLACE;
dss.back = dss.front;
break;
}
VkDynamicState dynamicStates[2];
VkDynamicState dynamicStates[5];
int numDyn = 0;
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_SCISSOR;
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_VIEWPORT;
if (depthStencilMode == VK2DDepthStencilMode::STENCIL_REPLACE_ALWAYS) {
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_STENCIL_WRITE_MASK;
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK;
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_STENCIL_REFERENCE;
}
VkPipelineDynamicStateCreateInfo ds = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
ds.pDynamicStates = dynamicStates;
@@ -290,10 +291,10 @@ VkPipeline Vulkan2D::GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShade
ibd.stride = vertexStride;
VkPipelineVertexInputStateCreateInfo vis = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
vis.vertexBindingDescriptionCount = 1;
vis.pVertexBindingDescriptions = &ibd;
vis.vertexAttributeDescriptionCount = attributeCount;
vis.pVertexAttributeDescriptions = attrs;
vis.vertexBindingDescriptionCount = readVertices ? 1 : 0;
vis.pVertexBindingDescriptions = readVertices ? &ibd : nullptr;
vis.vertexAttributeDescriptionCount = readVertices ? attributeCount : 0;
vis.pVertexAttributeDescriptions = readVertices ? attrs : nullptr;
VkPipelineViewportStateCreateInfo views = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
views.viewportCount = 1;
@@ -311,7 +312,6 @@ VkPipeline Vulkan2D::GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShade
pipe.pDepthStencilState = &dss;
pipe.pRasterizationState = &rs;
// We will use dynamic viewport state.
pipe.pVertexInputState = &vis;
pipe.pViewportState = &views;
pipe.pTessellationState = nullptr;
@@ -325,7 +325,7 @@ VkPipeline Vulkan2D::GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShade
pipe.subpass = 0;
VkPipeline pipeline;
VkResult result = vkCreateGraphicsPipelines(vulkan_->GetDevice(), cache, 1, &pipe, nullptr, &pipeline);
VkResult result = vkCreateGraphicsPipelines(vulkan_->GetDevice(), pipelineCache_, 1, &pipe, nullptr, &pipeline);
if (result == VK_SUCCESS) {
pipelines_[key] = pipeline;
return pipeline;
@@ -334,11 +334,6 @@ VkPipeline Vulkan2D::GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShade
}
}
void Vulkan2D::BindDescriptorSet(VkCommandBuffer cmd, VkImageView tex1, VkSampler sampler1) {
VkDescriptorSet descSet = GetDescriptorSet(tex1, sampler1, VK_NULL_HANDLE, VK_NULL_HANDLE);
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &descSet, 0, nullptr);
}
VkShaderModule CompileShaderModule(VulkanContext *vulkan, VkShaderStageFlagBits stage, const char *code, std::string *error) {
std::vector<uint32_t> spirv;
bool success = GLSLtoSPV(stage, code, spirv, error);
+17 -36
View File
@@ -42,38 +42,13 @@
//
// Each FBO will get its own command buffer for each pass.
//
struct VulkanFBOPass {
VkCommandBuffer cmd;
};
class VulkanFBO {
public:
VulkanFBO();
~VulkanFBO();
// Depth-format is chosen automatically depending on hardware support.
// Color format will be 32-bit RGBA.
void Create(VulkanContext *vulkan, VkRenderPass rp_compatible, int width, int height, VkFormat colorFormat);
VulkanTexture *GetColor() { return color_; }
VulkanTexture *GetDepthStencil() { return depthStencil_; }
VkFramebuffer GetFramebuffer() { return framebuffer_; }
private:
VulkanTexture *color_;
VulkanTexture *depthStencil_;
// This point specifically to color and depth.
VkFramebuffer framebuffer_;
};
// Similar to a subset of Thin3D, but separate.
// This is used for things like postprocessing shaders, depal, etc.
// No UBO data is used, only PushConstants.
// No transform matrices, only post-proj coordinates.
// Two textures can be sampled.
// Some simplified depth/stencil modes available.
class Vulkan2D {
public:
Vulkan2D(VulkanContext *vulkan);
@@ -83,16 +58,20 @@ public:
void DeviceRestore(VulkanContext *vulkan);
void Shutdown();
VkPipeline GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShaderModule vs, VkShaderModule fs);
enum class VK2DDepthStencilMode {
NONE,
STENCIL_REPLACE_ALWAYS, // Does not draw to color.
};
// The only supported primitive is the triangle strip, for simplicity.
// ReadVertices can be used for vertex-less rendering where you generate verts in the vshader.
VkPipeline GetPipeline(VkRenderPass rp, VkShaderModule vs, VkShaderModule fs, bool readVertices = true, VK2DDepthStencilMode depthStencilMode = VK2DDepthStencilMode::NONE);
VkPipelineLayout GetPipelineLayout() const { return pipelineLayout_; }
void BeginFrame();
void EndFrame();
VkDescriptorSet GetDescriptorSet(VkImageView tex1, VkSampler sampler1, VkImageView tex2, VkSampler sampler2);
// Simple way
void BindDescriptorSet(VkCommandBuffer cmd, VkImageView tex1, VkSampler sampler1);
struct Vertex {
float x, y, z;
float u, v;
@@ -102,9 +81,10 @@ private:
void InitDeviceObjects();
void DestroyDeviceObjects();
VulkanContext *vulkan_;
VkDescriptorSetLayout descriptorSetLayout_;
VkPipelineLayout pipelineLayout_;
VulkanContext *vulkan_ = nullptr;
VkDescriptorSetLayout descriptorSetLayout_ = VK_NULL_HANDLE;
VkPipelineLayout pipelineLayout_ = VK_NULL_HANDLE;
VkPipelineCache pipelineCache_ = VK_NULL_HANDLE;
// Yes, another one...
struct DescriptorSetKey {
@@ -121,8 +101,10 @@ private:
VkShaderModule vs;
VkShaderModule fs;
VkRenderPass rp;
VK2DDepthStencilMode depthStencilMode;
bool readVertices;
bool operator < (const PipelineKey &other) const {
return std::tie(vs, fs, rp) < std::tie(other.vs, other.fs, other.rp);
return std::tie(vs, fs, rp, depthStencilMode, readVertices) < std::tie(other.vs, other.fs, other.rp, depthStencilMode, readVertices);
}
};
@@ -132,7 +114,6 @@ private:
};
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES];
int curFrame_ = 0;
std::map<PipelineKey, VkPipeline> pipelines_;
};
+2
View File
@@ -1007,6 +1007,8 @@ void EmuScreen::postRender() {
Draw::DrawContext *draw = screenManager()->getDrawContext();
if (!draw)
return;
if (invalid_)
draw->WipeQueue();
draw->EndFrame();
}
+10 -10
View File
@@ -46,61 +46,61 @@
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<WindowsTargetPlatformVersion>10.0.10586.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.10240.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
+12 -10
View File
@@ -46,61 +46,61 @@
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<WindowsTargetPlatformVersion>10.0.10586.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.10240.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -405,6 +405,7 @@
<ClInclude Include="..\..\Core\HLE\sceSsl.h" />
<ClInclude Include="..\..\Core\HLE\sceUmd.h" />
<ClInclude Include="..\..\Core\HLE\sceUsb.h" />
<ClInclude Include="..\..\Core\HLE\sceUsbCam.h" />
<ClInclude Include="..\..\Core\HLE\sceUsbGps.h" />
<ClInclude Include="..\..\Core\HLE\sceUtility.h" />
<ClInclude Include="..\..\Core\HLE\sceVaudio.h" />
@@ -596,6 +597,7 @@
<ClCompile Include="..\..\Core\HLE\sceSsl.cpp" />
<ClCompile Include="..\..\Core\HLE\sceUmd.cpp" />
<ClCompile Include="..\..\Core\HLE\sceUsb.cpp" />
<ClCompile Include="..\..\Core\HLE\sceUsbCam.cpp" />
<ClCompile Include="..\..\Core\HLE\sceUsbGps.cpp" />
<ClCompile Include="..\..\Core\HLE\sceUtility.cpp" />
<ClCompile Include="..\..\Core\HLE\sceVaudio.cpp" />
+6
View File
@@ -617,6 +617,9 @@
<Filter>MIPS\IR</Filter>
</ClCompile>
<ClCompile Include="..\..\Core\AVIDump.cpp" />
<ClCompile Include="..\..\Core\HLE\sceUsbCam.cpp">
<Filter>HLE</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
@@ -1152,5 +1155,8 @@
<Filter>MIPS\IR</Filter>
</ClInclude>
<ClInclude Include="..\..\Core\AVIDump.h" />
<ClInclude Include="..\..\Core\HLE\sceUsbCam.h">
<Filter>HLE</Filter>
</ClInclude>
</ItemGroup>
</Project>
+10 -10
View File
@@ -46,61 +46,61 @@
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<WindowsTargetPlatformVersion>10.0.10586.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.10240.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
+12 -11
View File
@@ -46,61 +46,61 @@
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<WindowsTargetPlatformVersion>10.0.10586.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.10240.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -1180,6 +1180,7 @@
<ClCompile Include="..\..\ext\native\input\gesture_detector.cpp" />
<ClCompile Include="..\..\ext\native\input\input_state.cpp" />
<ClCompile Include="..\..\ext\native\math\curves.cpp" />
<ClCompile Include="..\..\ext\native\math\dataconv.cpp" />
<ClCompile Include="..\..\ext\native\math\expression_parser.cpp" />
<ClCompile Include="..\..\ext\native\math\fast\fast_math.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
@@ -1315,4 +1316,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
+4 -1
View File
@@ -454,6 +454,9 @@
<ClCompile Include="..\..\ext\native\base\logging.cpp">
<Filter>base</Filter>
</ClCompile>
<ClCompile Include="..\..\ext\native\math\dataconv.cpp">
<Filter>math</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
@@ -720,4 +723,4 @@
<Filter>gfx</Filter>
</ClInclude>
</ItemGroup>
</Project>
</Project>
+3
View File
@@ -1,6 +1,7 @@
#include "pch.h"
#include "PPSSPP_UWPMain.h"
#include <cassert>
#include <mutex>
#include "base/basictypes.h"
@@ -323,6 +324,8 @@ void PPSSPP_UWPMain::LoadStorageFile(StorageFile ^file) {
UWPGraphicsContext::UWPGraphicsContext(std::shared_ptr<DX::DeviceResources> resources) {
draw_ = Draw::T3DCreateD3D11Context(
resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetDeviceFeatureLevel(), 0);
bool success = draw_->CreatePresets();
assert(success);
}
void UWPGraphicsContext::Shutdown() {
+10 -10
View File
@@ -46,61 +46,61 @@
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<WindowsTargetPlatformVersion>10.0.10586.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.10240.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
-12
View File
@@ -137,18 +137,6 @@ void StorageFileLoader::EnsureOpen() {
Sleep(100);
}
// Note that multithreaded use could wreak havoc with this...
void StorageFileLoader::Seek(s64 absolutePos) {
EnsureOpen();
seekPos_ = absolutePos;
}
size_t StorageFileLoader::Read(size_t bytes, size_t count, void *data, Flags flags) {
size_t bytesRead = ReadAt(seekPos_, bytes, count, data, flags);
seekPos_ += bytesRead;
return bytesRead;
}
size_t StorageFileLoader::ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags) {
EnsureOpen();
if (operationRequested_ || responseAvailable_)
+1 -3
View File
@@ -26,9 +26,7 @@ public:
s64 FileSize() override;
std::string Path() const override;
std::string Extension() override;
void Seek(s64 absolutePos) override;
size_t Read(size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override;
size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override;
private:
@@ -87,4 +85,4 @@ private:
class StorageDirectoryWrapper {
private:
std::thread thread_;
};
};
+10 -10
View File
@@ -46,61 +46,61 @@
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<WindowsTargetPlatformVersion>10.0.10586.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.10240.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
+10 -10
View File
@@ -46,67 +46,67 @@
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<WindowsTargetPlatformVersion>10.0.10586.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.10240.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<ProjectName>PPSSPP_UWP</ProjectName>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|ARM'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-4
View File
@@ -176,10 +176,6 @@ bool UWPHost::CreateDesktopShortcut(std::string argumentPath, std::string gameTi
return false;
}
void UWPHost::GoFullscreen(bool viewFullscreen) {
// TODO
}
void UWPHost::ToggleDebugConsoleVisibility() {
// N/A
}
-2
View File
@@ -44,8 +44,6 @@ public:
void NotifyUserMessage(const std::string &message, float duration = 1.0f, u32 color = 0x00FFFFFF, const char *id = nullptr) override;
void GoFullscreen(bool) override;
GraphicsContext *GetGraphicsContext() { return nullptr; }
private:
+10 -10
View File
@@ -46,61 +46,61 @@
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<WindowsTargetPlatformVersion>10.0.10586.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.10240.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
+10 -10
View File
@@ -46,61 +46,61 @@
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<WindowsTargetPlatformVersion>10.0.10586.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.10240.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
+10 -10
View File
@@ -46,61 +46,61 @@
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<WindowsTargetPlatformVersion>10.0.10586.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.10240.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='UWP Gold|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
+1 -2
View File
@@ -61,8 +61,7 @@ void CGEDebugger::Init() {
}
CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent)
: Dialog((LPCSTR)IDD_GEDEBUGGER, _hInstance, _hParent), primaryWindow(nullptr), secondWindow(nullptr),
textureLevel_(0), showClut_(false), primaryBuffer_(nullptr), secondBuffer_(nullptr) {
: Dialog((LPCSTR)IDD_GEDEBUGGER, _hInstance, _hParent) {
GPUBreakpoints::Init();
Core_ListenShutdown(ForceUnpause);
+18 -18
View File
@@ -85,25 +85,25 @@ private:
u32 TexturePreviewFlags(const GPUgstate &state);
CtrlDisplayListView *displayList;
TabDisplayLists *lists;
TabStateFlags *flags;
TabStateLighting *lighting;
TabStateTexture *textureState;
TabStateSettings *settings;
TabVertices *vertices;
TabMatrices *matrices;
SimpleGLWindow *primaryWindow;
SimpleGLWindow *secondWindow;
TabStateWatch *watch;
TabControl *tabs;
TabControl *fbTabs;
int textureLevel_;
bool showClut_;
bool forceOpaque_;
CtrlDisplayListView *displayList = nullptr;
TabDisplayLists *lists = nullptr;
TabStateFlags *flags = nullptr;
TabStateLighting *lighting = nullptr;
TabStateTexture *textureState = nullptr;
TabStateSettings *settings = nullptr;
TabVertices *vertices = nullptr;
TabMatrices *matrices = nullptr;
SimpleGLWindow *primaryWindow = nullptr;
SimpleGLWindow *secondWindow = nullptr;
TabStateWatch *watch = nullptr;
TabControl *tabs = nullptr;
TabControl *fbTabs = nullptr;
int textureLevel_ = 0;
bool showClut_ = false;
bool forceOpaque_ = false;
// The most recent primary/framebuffer and texture buffers.
const GPUDebugBuffer *primaryBuffer_;
const GPUDebugBuffer *secondBuffer_;
const GPUDebugBuffer *primaryBuffer_ = nullptr;
const GPUDebugBuffer *secondBuffer_ = nullptr;
int minWidth_;
int minHeight_;
+3 -4
View File
@@ -2,6 +2,7 @@
#include "Common/CommonWindows.h"
#include <d3d11.h>
#include <cassert>
#include "base/logging.h"
#include "util/text/utf8.h"
@@ -27,10 +28,6 @@ D3D11Context::~D3D11Context() {
void D3D11Context::SwapBuffers() {
swapChain_->Present(0, 0);
draw_->HandleEvent(Draw::Event::PRESENTED, 0, 0, nullptr, nullptr);
// Might be a good idea.
// context_->ClearState();
//
}
void D3D11Context::SwapInterval(int interval) {
@@ -143,6 +140,8 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) {
#endif
draw_ = Draw::T3DCreateD3D11Context(device_, context_, device1_, context1_, featureLevel_, hWnd_);
bool success = draw_->CreatePresets(); // If we can run D3D11, there's a compiler installed. I think.
assert(success);
int width;
int height;
+7
View File
@@ -165,6 +165,13 @@ bool D3D9Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) {
//deviceEx->SetMaximumFrameLatency(1);
}
draw_ = Draw::T3DCreateDX9Context(d3d_, d3dEx_, adapterId_, device_, deviceEx_);
if (!draw_->CreatePresets()) {
// Shader compiler not installed? Return an error so we can fall back to GL.
device_->Release();
d3d_->Release();
*error_message = "DirectX9 runtime not correctly installed. Please install.";
return false;
}
if (draw_)
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, 0, 0, nullptr);
return true;
+3 -2
View File
@@ -15,8 +15,7 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
// TODO: What a mess this is :(
#include <cassert>
#include "Common/Log.h"
#include "Common/CommonWindows.h"
#include "gfx/gl_common.h"
@@ -358,6 +357,8 @@ bool WindowsGLContext::Init(HINSTANCE hInst, HWND window, std::string *error_mes
CheckGLExtensions();
draw_ = Draw::T3DCreateGLContext();
bool success = draw_->CreatePresets(); // if we get this far, there will always be a GLSL compiler capable of compiling these.
assert(success);
CHECK_GL_ERROR_IF_DEBUG();
return true; // Success
}
+20 -15
View File
@@ -124,19 +124,11 @@ static VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugRep
}
message << "[" << pLayerPrefix << "] " << ObjTypeToString(objType) << " Code " << msgCode << " : " << pMsg << "\n";
if (msgCode == 2) // Useless perf warning
if (msgCode == 2) // Useless perf warning ("Vertex attribute at location X not consumed by vertex shader")
return false;
// This seems like a bogus result when submitting two command buffers in one go, one creating the image, the other one using it.
if (msgCode == 6 && startsWith(pMsg, "Cannot submit cmd buffer using image"))
if (msgCode == 64) // Another useless perf warning that will be seen less and less as we optimize - vkCmdClearAttachments() issued on command buffer object 0x00000195296C6D40 prior to any Draw Cmds. It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw.
return false;
if (msgCode == 11)
return false;
// Silence "invalid reads of buffer data" - usually just uninitialized color buffers that will immediately get cleared due to our
// lacking clearing optimizations.
if (msgCode == 15 && objType == VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT)
return false;
#ifdef _WIN32
std::string msg = message.str();
OutputDebugStringA(msg.c_str());
@@ -180,7 +172,13 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m
Version gitVer(PPSSPP_GIT_VERSION);
g_Vulkan = new VulkanContext();
if (VK_SUCCESS != g_Vulkan->CreateInstance("PPSSPP", gitVer.ToInteger(), (g_validate_ ? VULKAN_FLAG_VALIDATE : 0) | VULKAN_FLAG_PRESENT_MAILBOX)) {
// int vulkanFlags = VULKAN_FLAG_PRESENT_FIFO_RELAXED;
int vulkanFlags = VULKAN_FLAG_PRESENT_MAILBOX;
if (g_validate_) {
vulkanFlags |= VULKAN_FLAG_VALIDATE;
}
if (VK_SUCCESS != g_Vulkan->CreateInstance("PPSSPP", gitVer.ToInteger(), vulkanFlags)) {
*error_message = g_Vulkan->InitError();
return false;
}
@@ -197,17 +195,21 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m
g_Vulkan->InitDebugMsgCallback(&Vulkan_Dbg, bits, &g_LogOptions);
}
g_Vulkan->InitSurfaceWin32(hInst, hWnd);
if (!g_Vulkan->InitObjects(true)) {
if (!g_Vulkan->InitObjects()) {
Shutdown();
return false;
}
draw_ = Draw::T3DCreateVulkanContext(g_Vulkan);
bool success = draw_->CreatePresets();
assert(success); // Doesn't fail, we include the compiler.
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
return true;
}
void WindowsVulkanContext::Shutdown() {
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
delete draw_;
draw_ = nullptr;
@@ -226,10 +228,13 @@ void WindowsVulkanContext::SwapBuffers() {
void WindowsVulkanContext::Resize() {
g_Vulkan->WaitUntilQueueIdle();
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
g_Vulkan->DestroyObjects();
g_Vulkan->ReinitSurfaceWin32();
g_Vulkan->InitObjects(true);
g_Vulkan->InitObjects();
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
}
void WindowsVulkanContext::SwapInterval(int interval) {
+1 -1
View File
@@ -8,7 +8,7 @@
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="25" />
android:targetSdkVersion="26" />
<uses-feature android:glEsVersion="0x00020000" />
<uses-feature android:name="android.hardware.screen.landscape" android:required="false" />
+4 -5
View File
@@ -35,8 +35,8 @@ android {
}
}
}
compileSdkVersion 25
buildToolsVersion '25.0.0'
compileSdkVersion 26
buildToolsVersion '27.0.0'
defaultConfig {
applicationId 'org.ppsspp.ppsspp'
if (androidGitVersion.name() != "unknown" && androidGitVersion.code() >= 14000000) {
@@ -52,14 +52,13 @@ android {
new File("versioncode.txt").write(androidGitVersion.code().toString())
minSdkVersion 9
targetSdkVersion 25
targetSdkVersion 26
if (project.hasProperty("ANDROID_VERSION_CODE") && project.hasProperty("ANDROID_VERSION_NAME")) {
versionCode ANDROID_VERSION_CODE
versionName ANDROID_VERSION_NAME
}
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86'
// Disabled 'x86_64' due to reported crash issues I can't debug without a device.
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
signingConfig signingConfigs.debug
}
+2
View File
@@ -136,6 +136,7 @@ VULKAN_FILES := \
$(SRC)/GPU/Vulkan/PipelineManagerVulkan.cpp \
$(SRC)/GPU/Vulkan/ShaderManagerVulkan.cpp \
$(SRC)/GPU/Vulkan/StateMappingVulkan.cpp \
$(SRC)/GPU/Vulkan/StencilBufferVulkan.cpp \
$(SRC)/GPU/Vulkan/TextureCacheVulkan.cpp \
$(SRC)/GPU/Vulkan/TextureScalerVulkan.cpp \
$(SRC)/GPU/Vulkan/DepalettizeShaderVulkan.cpp \
@@ -222,6 +223,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/GPU/Common/TextureCacheCommon.cpp.arm \
$(SRC)/GPU/Common/TextureScalerCommon.cpp.arm \
$(SRC)/GPU/Common/ShaderCommon.cpp \
$(SRC)/GPU/Common/StencilCommon.cpp \
$(SRC)/GPU/Common/SplineCommon.cpp.arm \
$(SRC)/GPU/Common/DrawEngineCommon.cpp.arm \
$(SRC)/GPU/Common/TransformCommon.cpp.arm \
Loaded 100 of 137 files, more files were not shown because too many files have changed in this diff. Show more