Files
workinf_Blender_Wasm/blender-5.2.0/intern/ghost/intern/GHOST_XrGraphicsBindingMetal.mm
2026-08-12 04:47:48 -04:00

167 lines
5.5 KiB
Plaintext

/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup GHOST
*/
#include "GHOST_ContextMTL.hh"
#include "GHOST_XrGraphicsBindingMetal.hh"
static std::optional<int64_t> choose_swapchain_format_from_candidates(
const std::vector<int64_t> &gpu_binding_formats, const std::vector<int64_t> &runtime_formats)
{
if (gpu_binding_formats.empty()) {
return std::nullopt;
}
auto res = std::find_first_of(gpu_binding_formats.begin(),
gpu_binding_formats.end(),
runtime_formats.begin(),
runtime_formats.end());
if (res == gpu_binding_formats.end()) {
return std::nullopt;
}
return *res;
}
GHOST_XrGraphicsBindingMetal::GHOST_XrGraphicsBindingMetal(GHOST_Context &ghost_ctx)
{
ghost_metal_ctx_ = dynamic_cast<GHOST_ContextMTL *>(&ghost_ctx);
}
bool GHOST_XrGraphicsBindingMetal::loadExtensionFunctions(XrInstance instance)
{
#define LOAD_FUNCTION(fn_ptr, name) \
if (XR_FAILED(xrGetInstanceProcAddr(instance, #name, (PFN_xrVoidFunction *)&fn_ptr))) { \
return false; \
}
LOAD_FUNCTION(xrGetMetalGraphicsRequirementsKHR_, xrGetMetalGraphicsRequirementsKHR);
#undef LOAD_FUNCTION
return true;
}
bool GHOST_XrGraphicsBindingMetal::checkVersionRequirements(GHOST_Context &ghost_ctx,
XrInstance instance,
XrSystemId system_id,
std::string *r_requirement_info) const
{
XrGraphicsRequirementsMetalKHR gpu_requirements;
gpu_requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_METAL_KHR;
gpu_requirements.next = nullptr;
gpu_requirements.metalDevice = nullptr;
xrGetMetalGraphicsRequirementsKHR_(instance, system_id, &gpu_requirements);
GHOST_ContextMTL &ghost_metal_ctx = dynamic_cast<GHOST_ContextMTL &>(ghost_ctx);
const bool metal_devices_match = (ghost_metal_ctx.metalDevice() == gpu_requirements.metalDevice);
if (!metal_devices_match) {
*r_requirement_info = "Metal Render Device used by Blender and OpenXR do not match";
return false;
}
return true;
}
void GHOST_XrGraphicsBindingMetal::initFromGhostContext(GHOST_Context &ghost_ctx,
XrInstance /*instance*/,
XrSystemId /*system_id*/)
{
GHOST_ContextMTL &ghost_metal_ctx = dynamic_cast<GHOST_ContextMTL &>(ghost_ctx);
oxr_binding.metal.type = XR_TYPE_GRAPHICS_BINDING_METAL_KHR;
oxr_binding.metal.next = nullptr;
oxr_binding.metal.commandQueue = (__bridge void *)ghost_metal_ctx.metalCommandQueue();
}
std::optional<int64_t> GHOST_XrGraphicsBindingMetal::chooseSwapchainFormat(
const std::vector<int64_t> &runtime_formats,
GHOST_TXrSwapchainFormat &r_format,
bool &r_is_srgb_format) const
{
std::vector<int64_t> gpu_binding_formats = {
MTLPixelFormatRGBA16Float,
MTLPixelFormatRGB10A2Unorm,
MTLPixelFormatRGBA16Unorm,
MTLPixelFormatRGBA8Unorm,
MTLPixelFormatRGBA8Unorm_sRGB,
};
const std::optional result = choose_swapchain_format_from_candidates(gpu_binding_formats,
runtime_formats);
if (!result) {
r_format = GHOST_kXrSwapchainFormatRGBA8;
r_is_srgb_format = false;
return result;
}
switch (*result) {
case MTLPixelFormatRGB10A2Unorm:
r_format = GHOST_kXrSwapchainFormatRGB10_A2;
break;
case MTLPixelFormatRGBA16Unorm:
r_format = GHOST_kXrSwapchainFormatRGBA16;
break;
case MTLPixelFormatRGBA16Float:
r_format = GHOST_kXrSwapchainFormatRGBA16F;
break;
case MTLPixelFormatRGBA8Unorm:
case MTLPixelFormatRGBA8Unorm_sRGB:
r_format = GHOST_kXrSwapchainFormatRGBA8;
break;
}
r_is_srgb_format = (*result == MTLPixelFormatRGBA8Unorm_sRGB);
return result;
}
std::vector<XrSwapchainImageBaseHeader *> GHOST_XrGraphicsBindingMetal::createSwapchainImages(
uint32_t image_count)
{
std::vector<XrSwapchainImageMetalKHR> metal_images(image_count);
std::vector<XrSwapchainImageBaseHeader *> base_images;
/* Need to return vector of base header pointers, so of a different type. Need to build a new
* list with this type, and keep the initial one alive. */
for (XrSwapchainImageMetalKHR &image : metal_images) {
image.type = XR_TYPE_SWAPCHAIN_IMAGE_METAL_KHR;
base_images.push_back(reinterpret_cast<XrSwapchainImageBaseHeader *>(&image));
}
/* Keep alive. */
image_cache_.push_back(std::move(metal_images));
return base_images;
}
void GHOST_XrGraphicsBindingMetal::submitToSwapchainBegin() {}
void GHOST_XrGraphicsBindingMetal::submitToSwapchainImage(
XrSwapchainImageBaseHeader &swapchain_image, const GHOST_XrDrawViewInfo &draw_info)
{
XrSwapchainImageMetalKHR &metal_swapchain_image = reinterpret_cast<XrSwapchainImageMetalKHR &>(
swapchain_image);
id<MTLTexture> metal_xr_texture = static_cast<id<MTLTexture>>(metal_swapchain_image.texture);
ghost_metal_ctx_->xrBlitCallback(
metal_xr_texture, draw_info.ofsx, draw_info.ofsy, draw_info.width, draw_info.height);
}
void GHOST_XrGraphicsBindingMetal::submitToSwapchainEnd() {}
bool GHOST_XrGraphicsBindingMetal::needsUpsideDownDrawing(GHOST_Context &ghost_ctx) const
{
GHOST_ContextMTL &ghost_metal_ctx = dynamic_cast<GHOST_ContextMTL &>(ghost_ctx);
return !ghost_metal_ctx.isUpsideDown();
}