mirror of
https://github.com/libretro/parallel-dc.git
synced 2026-11-09 17:28:17 -10:00
Their pixels are written into the texture's piece of the upload ring, which the upload then takes as it is, instead of on the stack and copied there.
225 lines
6.9 KiB
C++
225 lines
6.9 KiB
C++
#define PVR_REGS_FOR_RENDERER // see hw/pvr/pvr_regs.h
|
|
/*
|
|
Created on: Dec 13, 2019
|
|
|
|
Copyright 2019 flyinghead
|
|
|
|
This file is part of Flycast.
|
|
|
|
Flycast 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, either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Flycast 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 for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "vmu.h"
|
|
#include "texture.h"
|
|
|
|
VulkanOSD::~VulkanOSD()
|
|
{
|
|
}
|
|
|
|
const std::vector<vk::CommandBuffer>* VulkanOSD::PrepareOSD(CommandPool *commandPool)
|
|
{
|
|
VulkanContext *context = VulkanContext::Instance();
|
|
const size_t imageIndex = context->GetCurrentImageIndex();
|
|
if (commandBuffers.size() <= imageIndex)
|
|
commandBuffers.resize(std::max((size_t)context->GetSwapChainSize(), imageIndex + 1));
|
|
commandBuffers[imageIndex].clear();
|
|
for (int i = 0; i < VMU_COUNT; i++)
|
|
{
|
|
std::unique_ptr<Texture>& texture = vmuTextures[i];
|
|
auto& vmu_screen_param = vmu_screen_params[i];
|
|
|
|
// A new picture from the game, if there is one
|
|
const bool lcd_changed = vmu_lcd_refresh(i);
|
|
|
|
if (!vmu_screen_param.vmu_screen_display || vmu_lcd_pixels(i) == nullptr)
|
|
{
|
|
texture.reset();
|
|
continue;
|
|
}
|
|
if (!texture)
|
|
texture = std::unique_ptr<Texture>(new Texture());
|
|
else if (!lcd_changed && !vmu_screen_param.vmu_screen_needs_update)
|
|
continue;
|
|
|
|
texture->tex_type = TextureType::_8888;
|
|
texture->SetDevice(context->GetDevice());
|
|
texture->SetPhysicalDevice(context->GetPhysicalDevice());
|
|
/* (made straight in the upload ring's piece for it, which the
|
|
* upload then takes as it is; on the stack if it has no room) */
|
|
u8 temp_tex_buffer[VMU_SCREEN_HEIGHT * VMU_SCREEN_WIDTH * 4];
|
|
u8 *pixels = (u8 *)texture->UploadMemory(VMU_SCREEN_WIDTH, VMU_SCREEN_HEIGHT, sizeof(temp_tex_buffer), 4, false);
|
|
if (pixels == nullptr)
|
|
pixels = temp_tex_buffer;
|
|
u8 *dst = pixels;
|
|
const u8 *src = vmu_lcd_pixels(i);
|
|
|
|
for (int y = 0; y < VMU_SCREEN_HEIGHT; y++)
|
|
{
|
|
for (int x = 0; x < VMU_SCREEN_WIDTH; x++)
|
|
{
|
|
if (*src++)
|
|
{
|
|
*dst++ = vmu_screen_param.vmu_pixel_on_R;
|
|
*dst++ = vmu_screen_param.vmu_pixel_on_G;
|
|
*dst++ = vmu_screen_param.vmu_pixel_on_B;
|
|
}
|
|
else
|
|
{
|
|
*dst++ = vmu_screen_param.vmu_pixel_off_R;
|
|
*dst++ = vmu_screen_param.vmu_pixel_off_G;
|
|
*dst++ = vmu_screen_param.vmu_pixel_off_B;
|
|
}
|
|
*dst++ = 0xff;
|
|
}
|
|
}
|
|
|
|
commandBuffers[context->GetCurrentImageIndex()].push_back(commandPool->Allocate());
|
|
texture->SetCommandBuffer(commandBuffers[context->GetCurrentImageIndex()].back());
|
|
texture->UploadToGPU(VMU_SCREEN_WIDTH, VMU_SCREEN_HEIGHT, pixels, false);
|
|
texture->SetCommandBuffer(nullptr);
|
|
vmu_screen_param.vmu_screen_needs_update = false;
|
|
}
|
|
|
|
for (int i = 0; i < XHAIR_COUNT; i++)
|
|
{
|
|
std::unique_ptr<Texture>& texture = xhairTextures[i];
|
|
if (lightgun_params[i].offscreen || lightgun_params[i].colour == 0)
|
|
{
|
|
texture.reset();
|
|
continue;
|
|
}
|
|
if (!texture)
|
|
texture = std::unique_ptr<Texture>(new Texture());
|
|
else if (!lightgun_params[i].dirty)
|
|
continue;
|
|
|
|
texture->tex_type = TextureType::_8888;
|
|
texture->SetDevice(context->GetDevice());
|
|
texture->SetPhysicalDevice(context->GetPhysicalDevice());
|
|
// (as the VMUs')
|
|
u8 temp_tex_buffer[LIGHTGUN_CROSSHAIR_SIZE * LIGHTGUN_CROSSHAIR_SIZE * 4];
|
|
u8 *pixels = (u8 *)texture->UploadMemory(LIGHTGUN_CROSSHAIR_SIZE, LIGHTGUN_CROSSHAIR_SIZE, sizeof(temp_tex_buffer), 4, false);
|
|
if (pixels == nullptr)
|
|
pixels = temp_tex_buffer;
|
|
u8 *dst = pixels;
|
|
u8* colour = &lightgun_palette[lightgun_params[i].colour * 3];
|
|
u8 *src = lightgun_img_crosshair;
|
|
|
|
for (int y = 0; y < LIGHTGUN_CROSSHAIR_SIZE; y++)
|
|
{
|
|
for (int x = 0; x < LIGHTGUN_CROSSHAIR_SIZE; x++)
|
|
{
|
|
if (*src++)
|
|
{
|
|
*dst++ = colour[0];
|
|
*dst++ = colour[1];
|
|
*dst++ = colour[2];
|
|
*dst++ = 0xFF;
|
|
}
|
|
else
|
|
{
|
|
*dst++ = 0;
|
|
*dst++ = 0;
|
|
*dst++ = 0;
|
|
*dst++ = 0;
|
|
}
|
|
}
|
|
}
|
|
commandBuffers[context->GetCurrentImageIndex()].push_back(commandPool->Allocate());
|
|
texture->SetCommandBuffer(commandBuffers[context->GetCurrentImageIndex()].back());
|
|
texture->UploadToGPU(LIGHTGUN_CROSSHAIR_SIZE, LIGHTGUN_CROSSHAIR_SIZE, pixels, false);
|
|
texture->SetCommandBuffer(nullptr);
|
|
lightgun_params[i].dirty = false;
|
|
}
|
|
return &commandBuffers[context->GetCurrentImageIndex()];
|
|
}
|
|
|
|
void VulkanOSD::DrawOSD(vk::CommandBuffer commandBuffer, vk::Extent2D viewport, CommandPool *commandPool, QuadPipeline *with)
|
|
{
|
|
(with != nullptr ? with : pipeline)->BindPipeline(commandBuffer, false);
|
|
QuadVertex vtx[] = {
|
|
{ { -1.f, -1.f, 0.f }, { 0.f, 1.f } },
|
|
{ { 1.f, -1.f, 0.f }, { 1.f, 1.f } },
|
|
{ { -1.f, 1.f, 0.f }, { 0.f, 0.f } },
|
|
{ { 1.f, 1.f, 0.f }, { 1.f, 0.f } },
|
|
};
|
|
|
|
for (int i = 0; i < VMU_COUNT; i++)
|
|
{
|
|
if (!vmuTextures[i])
|
|
continue;
|
|
|
|
const auto& vmu_screen_param = vmu_screen_params[i];
|
|
float x = 0;
|
|
float y = 0;
|
|
float w = VMU_SCREEN_WIDTH * vmu_screen_param.vmu_screen_size_mult;
|
|
float h = VMU_SCREEN_HEIGHT * vmu_screen_param.vmu_screen_size_mult;
|
|
|
|
switch (vmu_screen_param.vmu_screen_position)
|
|
{
|
|
case UPPER_LEFT:
|
|
x = 0;
|
|
y = 0;
|
|
break;
|
|
|
|
case UPPER_RIGHT:
|
|
x = viewport.width - w;
|
|
y = 0;
|
|
break;
|
|
|
|
case LOWER_LEFT:
|
|
x = 0;
|
|
y = viewport.height - h;
|
|
break;
|
|
|
|
case LOWER_RIGHT:
|
|
x = viewport.width - w;
|
|
y = viewport.height - h;
|
|
break;
|
|
}
|
|
|
|
vk::Viewport viewport(x, y, w, h);
|
|
commandBuffer.setViewport(0, 1, &viewport);
|
|
commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(x, y), vk::Extent2D(w, h)));
|
|
|
|
float alpha = vmu_screen_param.vmu_screen_opacity / 255.f;
|
|
float blendConstants[4] = { alpha, alpha, alpha, alpha };
|
|
commandBuffer.setBlendConstants(blendConstants);
|
|
|
|
drawers[i]->Draw(commandBuffer, vmuTextures[i]->GetImageView(), vtx, true, commandPool);
|
|
}
|
|
|
|
pipeline->BindPipeline(commandBuffer, true);
|
|
for (int i = 0; i < XHAIR_COUNT; i++)
|
|
{
|
|
if (!xhairTextures[i])
|
|
continue;
|
|
|
|
float w = LIGHTGUN_CROSSHAIR_SIZE;
|
|
float h = LIGHTGUN_CROSSHAIR_SIZE;
|
|
// (the game's 640x480 is in the middle of a widescreen picture)
|
|
float sidebar = (viewport.width - viewport.height * 4.f / 3.f) / 2;
|
|
float x = sidebar + lightgun_params[i].x * viewport.height / 480 - w / 2;
|
|
float y = lightgun_params[i].y * viewport.height / 480 - h / 2;
|
|
|
|
vk::Viewport viewport(x, y, w, h);
|
|
commandBuffer.setViewport(0, 1, &viewport);
|
|
commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(x, y), vk::Extent2D(w, h)));
|
|
|
|
float blendConstants[4] = { 1.f, 1.f, 1.f, 1.f };
|
|
commandBuffer.setBlendConstants(blendConstants);
|
|
|
|
xhairDrawers[i]->Draw(commandBuffer, xhairTextures[i]->GetImageView(), vtx, true, commandPool);
|
|
}
|
|
}
|