mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-15 02:29:51 +01:00
Merge branch 'master' into TemporaryHackishBranch
# Conflicts: # GPU/GLES/FramebufferManagerGLES.cpp ~Due to restoration of the BGRA path
This commit is contained in:
commit
5f3d6c57dd
137 files changed
+4731
-4088
No files matched your search
+1
-1
@@ -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.
|
||||
|
||||
@@ -37,6 +37,7 @@ PPSSPPDebug64.exe.manifest
|
||||
PPSSPPDebug.exe.manifest
|
||||
assets/flash0
|
||||
UWP/icph
|
||||
UWP/.vs
|
||||
|
||||
# For Mac
|
||||
.DS_Store
|
||||
|
||||
+15
-3
@@ -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()
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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, ¤t_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 = ¤t_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:
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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, ©_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() {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
@@ -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" />
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -71,6 +71,10 @@ public:
|
||||
|
||||
void SetupVertexDecoder(u32 vertType);
|
||||
|
||||
bool IsCodePtrVertexDecoder(const u8 *ptr) const {
|
||||
return decJitCache_->IsInSpace(ptr);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void ClearTrackedVertexArrays() {}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Whitespace-only changes.
@@ -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);
|
||||
}
|
||||
@@ -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_;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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(©Info, 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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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]{};
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -64,6 +64,7 @@ enum {
|
||||
struct VulkanPipeline {
|
||||
VkPipeline pipeline;
|
||||
int uniformBlocks; // UB_ enum above.
|
||||
bool useBlendConstant;
|
||||
};
|
||||
|
||||
class VulkanContext;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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
@@ -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
@@ -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_;
|
||||
};
|
||||
|
||||
@@ -1007,6 +1007,8 @@ void EmuScreen::postRender() {
|
||||
Draw::DrawContext *draw = screenManager()->getDrawContext();
|
||||
if (!draw)
|
||||
return;
|
||||
if (invalid_)
|
||||
draw->WipeQueue();
|
||||
draw->EndFrame();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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" />
|
||||
|
||||
@@ -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
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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() {
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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_)
|
||||
|
||||
@@ -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
@@ -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
@@ -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" />
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
Reference in new issue
Block a user