mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 20:58:31 +09:00
160 lines
6.6 KiB
C++
160 lines
6.6 KiB
C++
//
|
|
// Created by BZLZHH on 2025/3/15.
|
|
//
|
|
|
|
#include "MesaEmu.h"
|
|
|
|
// Code From DeepSeek
|
|
|
|
#include <vulkan/vulkan.h>
|
|
#include <cstring>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <stdexcept>
|
|
struct OSMesaContextData {
|
|
VkInstance instance = VK_NULL_HANDLE;
|
|
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
|
VkDevice device = VK_NULL_HANDLE;
|
|
VkQueue graphicsQueue = VK_NULL_HANDLE;
|
|
VkImage targetImage = VK_NULL_HANDLE;
|
|
VkImageView imageView = VK_NULL_HANDLE;
|
|
VkCommandPool commandPool = VK_NULL_HANDLE;
|
|
GLsizei currentWidth = 0;
|
|
GLsizei currentHeight = 0;
|
|
GLint packAlignment = 4;
|
|
GLubyte* frontBuffer = nullptr;
|
|
uint32_t queueFamilyIndex = 0;
|
|
};
|
|
static std::map<OSMesaContext, OSMesaContextData> ctxMap;
|
|
static thread_local OSMesaContext currentContext = nullptr;
|
|
static uint32_t findGraphicsQueueFamily(VkPhysicalDevice physicalDevice) {
|
|
uint32_t queueFamilyCount = 0;
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr);
|
|
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies.data());
|
|
for (uint32_t i = 0; i < queueFamilyCount; ++i) {
|
|
if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
|
return i;
|
|
}
|
|
}
|
|
throw std::runtime_error("No graphics queue family found");
|
|
}
|
|
extern "C" MG_EXPORT OSMesaContext OSMesaCreateContext(GLenum format, OSMesaContext sharelist) {
|
|
OSMesaContextData newCtx;
|
|
try {
|
|
VkInstanceCreateInfo instanceInfo{};
|
|
instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
|
if (vkCreateInstance(&instanceInfo, nullptr, &newCtx.instance) != VK_SUCCESS) {
|
|
throw std::runtime_error("Failed to create Vulkan instance");
|
|
}
|
|
uint32_t deviceCount = 0;
|
|
vkEnumeratePhysicalDevices(newCtx.instance, &deviceCount, nullptr);
|
|
if (deviceCount == 0) {
|
|
throw std::runtime_error("No Vulkan devices found");
|
|
}
|
|
|
|
std::vector<VkPhysicalDevice> devices(deviceCount);
|
|
vkEnumeratePhysicalDevices(newCtx.instance, &deviceCount, devices.data());
|
|
newCtx.physicalDevice = devices[0];
|
|
newCtx.queueFamilyIndex = findGraphicsQueueFamily(newCtx.physicalDevice);
|
|
float queuePriority = 1.0f;
|
|
VkDeviceQueueCreateInfo queueCreateInfo{};
|
|
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
queueCreateInfo.queueFamilyIndex = newCtx.queueFamilyIndex;
|
|
queueCreateInfo.queueCount = 1;
|
|
queueCreateInfo.pQueuePriorities = &queuePriority;
|
|
VkDeviceCreateInfo deviceInfo{};
|
|
deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
|
deviceInfo.queueCreateInfoCount = 1;
|
|
deviceInfo.pQueueCreateInfos = &queueCreateInfo;
|
|
if (vkCreateDevice(newCtx.physicalDevice, &deviceInfo, nullptr, &newCtx.device) != VK_SUCCESS) {
|
|
throw std::runtime_error("Failed to create logical device");
|
|
}
|
|
vkGetDeviceQueue(newCtx.device, newCtx.queueFamilyIndex, 0, &newCtx.graphicsQueue);
|
|
VkCommandPoolCreateInfo poolInfo{};
|
|
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
poolInfo.queueFamilyIndex = newCtx.queueFamilyIndex;
|
|
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
|
if (vkCreateCommandPool(newCtx.device, &poolInfo, nullptr, &newCtx.commandPool) != VK_SUCCESS) {
|
|
throw std::runtime_error("Failed to create command pool");
|
|
}
|
|
OSMesaContext ctx = reinterpret_cast<OSMesaContext>(new int(0));
|
|
ctxMap[ctx] = newCtx;
|
|
return ctx;
|
|
} catch (const std::exception& e) {
|
|
if (newCtx.device) vkDestroyDevice(newCtx.device, nullptr);
|
|
if (newCtx.instance) vkDestroyInstance(newCtx.instance, nullptr);
|
|
return nullptr;
|
|
}
|
|
}
|
|
extern "C" MG_EXPORT void OSMesaDestroyContext(OSMesaContext ctx) {
|
|
if (ctxMap.find(ctx) != ctxMap.end()) {
|
|
auto& data = ctxMap[ctx];
|
|
|
|
if (data.commandPool) {
|
|
vkDestroyCommandPool(data.device, data.commandPool, nullptr);
|
|
}
|
|
if (data.imageView) {
|
|
vkDestroyImageView(data.device, data.imageView, nullptr);
|
|
}
|
|
if (data.targetImage) {
|
|
vkDestroyImage(data.device, data.targetImage, nullptr);
|
|
}
|
|
if (data.device) {
|
|
vkDestroyDevice(data.device, nullptr);
|
|
}
|
|
if (data.instance) {
|
|
vkDestroyInstance(data.instance, nullptr);
|
|
}
|
|
|
|
ctxMap.erase(ctx);
|
|
delete reinterpret_cast<int*>(ctx);
|
|
}
|
|
}
|
|
extern "C" MG_EXPORT GLboolean OSMesaMakeCurrent(OSMesaContext ctx, void *buffer, GLenum type,
|
|
GLsizei width, GLsizei height) {
|
|
if (!ctx || !buffer || width <= 0 || height <= 0) return GL_FALSE;
|
|
auto& data = ctxMap[ctx];
|
|
data.currentWidth = width;
|
|
data.currentHeight = height;
|
|
data.frontBuffer = static_cast<GLubyte*>(buffer);
|
|
VkImageCreateInfo imageInfo{};
|
|
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
|
imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
|
|
imageInfo.extent = {static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1};
|
|
imageInfo.mipLevels = 1;
|
|
imageInfo.arrayLayers = 1;
|
|
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
imageInfo.tiling = VK_IMAGE_TILING_LINEAR;
|
|
imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
|
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
if (vkCreateImage(data.device, &imageInfo, nullptr, &data.targetImage) != VK_SUCCESS) {
|
|
return GL_FALSE;
|
|
}
|
|
VkImageViewCreateInfo viewInfo{};
|
|
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
viewInfo.image = data.targetImage;
|
|
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
viewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
|
|
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
viewInfo.subresourceRange.levelCount = 1;
|
|
viewInfo.subresourceRange.layerCount = 1;
|
|
if (vkCreateImageView(data.device, &viewInfo, nullptr, &data.imageView) != VK_SUCCESS) {
|
|
vkDestroyImage(data.device, data.targetImage, nullptr);
|
|
return GL_FALSE;
|
|
}
|
|
currentContext = ctx;
|
|
return GL_TRUE;
|
|
}
|
|
extern "C" MG_EXPORT OSMesaContext OSMesaGetCurrentContext() {
|
|
return currentContext;
|
|
}
|
|
extern "C" MG_EXPORT void OSMesaPixelStore(GLint pname, GLint value) {
|
|
if (pname == GL_PACK_ALIGNMENT && currentContext) {
|
|
ctxMap[currentContext].packAlignment = value;
|
|
}
|
|
}
|
|
extern "C" MG_EXPORT OSMESAproc OSMesaGetProcAddress( const char *funcName ) {
|
|
return (OSMESAproc)MG_GL::GLX::GetProcAddress(funcName);
|
|
} |