Skip to content

Commit

Permalink
looks like we needed an alpha channel in the swapchain to get framebu…
Browse files Browse the repository at this point in the history
…ffer complete
  • Loading branch information
ixchow committed Nov 16, 2023
1 parent d113416 commit 0f706df
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 22 deletions.
15 changes: 13 additions & 2 deletions Maekfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ maek.TARGETS = [game_exe, show_meshes_exe, show_scene_exe, ...copies];

//android sdk location:
const ANDROID_SDK = `../android-sdk`;
const OVR_OPENXR_SDK = `../ovr-openxr-sdk`;

//versions of various android sdk packages:
const NDK = `${ANDROID_SDK}/ndk/26.1.10909125`;
Expand All @@ -179,15 +180,19 @@ const android_options = {
'-Wall', '-Werror',
'-target', 'aarch64-linux-android29',
`-I`, `../nest-libs/linux/glm/include`,
`-I`, `../ovr-openxr-sdk/OpenXR/Include`,
`-I`, `../ovr-openxr-sdk/3rdParty/khronos/openxr/OpenXR-SDK/include`,
`-I`, `${OVR_OPENXR_SDK}/OpenXR/Include`,
`-I`, `${OVR_OPENXR_SDK}/3rdParty/khronos/openxr/OpenXR-SDK/include`,
`-I`, `${NDK}/sources/android/native_app_glue/`,
],
CPPFlags: [], //extra flags for c++ compiler
LINK: [
`${NDK}/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++`,
'-target', 'aarch64-linux-android29',
'-shared',
'-lEGL',
'-lGLESv3',
'-landroid',
`-L${OVR_OPENXR_SDK}/OpenXR/Libs/Android/arm64-v8a/Release/`, `-lopenxr_loader`,
'-Wl,-Bsymbolic', //look for global symbols inside library first
'-Wl,-soname,libgame.so', //specify name of output library (suggested by https://android.googlesource.com/platform/ndk/+/master/docs/BuildSystemMaintainers.md#Additional-Required-Arguments )
],
Expand All @@ -196,6 +201,12 @@ const android_options = {


const android_game_objs = game_sources.map((x) => maek.CPP(x, undefined, android_options));

//very much a hack:
android_options.CPP[0] = `${NDK}/toolchains/llvm/prebuilt/linux-x86_64/bin/clang`;
android_game_objs.push( maek.CPP(`${NDK}/sources/android/native_app_glue/android_native_app_glue.c`, `objs/android/android_native_app_glue.o`, android_options) );
android_options.CPP[0] = `${NDK}/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++`;

const android_common_objs = common_sources.map((x) => maek.CPP(x, undefined, android_options));

const android_game_so = maek.LINK([...android_game_objs, ...android_common_objs], 'objs/android/apk/lib/arm64-v8a/libgame.so', android_options);
Expand Down
85 changes: 73 additions & 12 deletions XR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@


#include <iostream>
#include <sstream>
#include <cstring>
#include <vector>
#include <array>
Expand All @@ -47,6 +48,22 @@ XR::XR(
) {
std::cout << "--- initializing OpenXR ---" << std::endl;

#ifdef __ANDROID__
{ //call xrInitializeLoaderKHR (based on XrApp.cpp from OVR OpenXR SDK):
PFN_xrInitializeLoaderKHR xrInitializeLoaderKHR;
xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", reinterpret_cast< PFN_xrVoidFunction* >(&xrInitializeLoaderKHR));
if (xrInitializeLoaderKHR != NULL) {
XrLoaderInitInfoAndroidKHR loader_init_info = {XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR};
loader_init_info.applicationVM = platform.application_vm;
loader_init_info.applicationContext = platform.application_activity; //TODO: is this right? OVR sample does it, but docs say this should be a "android.content.Context" (which seems different from the Activity below)
if (XrResult res = xrInitializeLoaderKHR(reinterpret_cast< XrLoaderInitInfoBaseHeaderKHR *>(&loader_init_info));
res != XR_SUCCESS) {
std::cerr << "WARNING: xrInitializeLoaderKHR failed: " << to_string(res) << std::endl;
}
}
}
#endif //__ANDROID__

XrInstanceCreateInfo create_info{XR_TYPE_INSTANCE_CREATE_INFO};

//with reference to openxr_program.cpp from openxr-sdk-source + the openxr specification
Expand All @@ -64,8 +81,15 @@ XR::XR(

create_info.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;

//TODO: ON ANROID --> set create_info->next to point to an XrInstanceCreateInfoAndroidKHR structure
// filled in as per openxr-sdk-source's platformplugin_android.cpp
#ifdef __ANDROID__
//extra android-specific creation info:
XrInstanceCreateInfoAndroidKHR create_info_android{XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR};

create_info_android.applicationVM = platform.application_vm;
create_info_android.applicationActivity = platform.application_activity;

create_info.next = &create_info_android;
#endif //__ANDROID__

std::vector< const char * > extensions{
#ifdef __ANDROID__
Expand Down Expand Up @@ -168,6 +192,7 @@ XR::XR(
GLint minor = 0;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
std::cout << "Current OpenGL version is " << major << "." << minor << std::endl;
if (XR_MAKE_VERSION(major, minor, 0) < graphics_requirements.minApiVersionSupported) {
std::cerr << "ERROR: reported OpenGL version (" << major << "." << minor << ") is less than the minimum that OpenXR reports as supporting. (Continuing, but don't expect things to work.)" << std::endl;
}
Expand Down Expand Up @@ -287,20 +312,28 @@ XR::XR(
}

{ //swapchain creation
std::array< int64_t, 64 > formats;
uint32_t format_capacity = uint32_t(formats.size());
uint32_t format_capacity = 0;
//query needed format capacity:
if (XrResult res = xrEnumerateSwapchainFormats(session, 0, &format_capacity, nullptr);
res != XR_SUCCESS) {
throw std::runtime_error("Failed to count swapchain formats: " + to_string(res));
}
//allocate enough space and get them:
std::vector< int64_t > formats(format_capacity, 0);
uint32_t format_count = 0;
if (XrResult res = xrEnumerateSwapchainFormats(session, format_capacity, &format_count, formats.data());
res != XR_SUCCESS) {
throw std::runtime_error("Failed to get enumerate swapchain formats: " + to_string(res));
throw std::runtime_error("Failed to enumerate swapchain formats: " + to_string(res));
}

bool have_SRGB8 = false;
GLenum wanted_format = GL_SRGB8_ALPHA8;
std::string wanted_format_name = "GL_SRGB8_ALPHA8"; //for error/info messages
bool have_wanted_format = false;

std::cout << "Got " << format_count << " swapchain formats." << std::endl;
for (uint32_t f = 0; f < format_count; ++f) {
int64_t format = formats[f];
if (format == GL_SRGB8) have_SRGB8 = true;
if (format == wanted_format) have_wanted_format = true;

std::cout << " [" << f << "]: ";
#define DO(fmt) if (format == fmt) { std::cout << #fmt; } else
Expand All @@ -315,17 +348,20 @@ XR::XR(
DO(GL_DEPTH_COMPONENT32F)
{ std::cout << " as-of-yet untranslated enum 0x" << std::hex << format << std::dec; }
std::cout << std::endl;
#undef DO
}

if (!have_SRGB8) {
throw std::runtime_error("GL_SRGB8 was not among the preferred formats; this code expects it to be.");
if (!have_wanted_format) {
throw std::runtime_error(wanted_format_name + " was not among the preferred formats; this code expects it to be.");
} else {
std::cerr << "Chose " << wanted_format_name << " for swapchain format." << std::endl;
}

XrSwapchainCreateInfo create_info{XR_TYPE_SWAPCHAIN_CREATE_INFO};

create_info.createFlags = 0;
create_info.usageFlags = XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_SAMPLED_BIT; //NOTE: USAGE_SAMPLED_BIT was used by the ovr sdk sample; not sure if this is actually needed
create_info.format = GL_SRGB8;
create_info.format = wanted_format;
create_info.sampleCount = 1;
create_info.width = size.x;
create_info.height = size.y;
Expand Down Expand Up @@ -362,6 +398,7 @@ XR::XR(
view.framebuffers.resize(images.size());
for (uint32_t i = 0; i < view.framebuffers.size(); ++i) {
view.framebuffers[i].color_tex = images[i].image;

//set texture sampling state: (ovr sdk sample does this; not sure if it is needed)
glBindTexture(GL_TEXTURE_2D, view.framebuffers[i].color_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
Expand All @@ -370,22 +407,46 @@ XR::XR(
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);

GL_ERRORS();

//allocate depth renderbuffer:
glGenRenderbuffers(1, &view.framebuffers[i].depth_rb);
glBindRenderbuffer(GL_RENDERBUFFER, view.framebuffers[i].depth_rb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size.x, size.y);
glBindRenderbuffer(GL_RENDERBUFFER, 0);

GL_ERRORS();

//allocate framebuffer:
glGenFramebuffers(1, &view.framebuffers[i].fb);
glBindFramebuffer(GL_FRAMEBUFFER, view.framebuffers[i].fb);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, view.framebuffers[i].depth_rb);
//glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, view.framebuffers[i].depth_rb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, view.framebuffers[i].color_tex, 0);

GL_ERRORS();

GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

if (status != GL_FRAMEBUFFER_COMPLETE) {
throw std::runtime_error("Failed to create a complete framebuffer " + std::to_string(status));
#define DO(name) \
if (status == name) { throw std::runtime_error("Failed to create a complete framebuffer:" + std::string(#name)); } else

DO(GL_FRAMEBUFFER_UNDEFINED);
DO(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
DO(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
DO(GL_FRAMEBUFFER_UNSUPPORTED);
DO(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE);
#ifndef __ANDROID__
DO(GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER);
DO(GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER);
DO(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS);
#endif
{
std::ostringstream str;
str << "0x" << std::hex << status;
throw std::runtime_error("Failed to create a complete framebuffer: unknown status " + str.str());
}
#undef DO
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);

Expand Down
63 changes: 55 additions & 8 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@

#ifdef __ANDROID__
#include <android_native_app_glue.h>
//#include <android/log.h>
//#include <unistd.h>
#include <android/log.h>
#include <unistd.h>

#else
//Includes for desktop platforms:
Expand All @@ -36,8 +36,6 @@

#ifdef __ANDROID__

/*
//This delightful redirect hack based on:
// https://codelab.wordpress.com/2014/11/03/how-to-use-standard-output-streams-for-logging-in-android-apps/

Expand Down Expand Up @@ -75,18 +73,17 @@ int start_logger() {
pthread_detach(thr);
return 0;
}
*/


//modeled on OpenXR's "hello_xr" example's main.cpp:
// https://github.com/KhronosGroup/OpenXR-SDK-Source/blob/main/src/tests/hello_xr/main.cpp
void android_main(struct android_app* app) {
/*

if (start_logger() != 0) {
__android_log_write(ANDROID_LOG_FATAL, tag, "Failed to start log thread!");
return;
}
*/

try {
JNIEnv* Env;
app->activity->vm->AttachCurrentThread(&Env, nullptr);
Expand Down Expand Up @@ -126,6 +123,8 @@ void android_main(struct android_app* app) {
EGL_SAMPLES, 0,
EGL_CONFORMANT, EGL_OPENGL_ES3_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
//EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE,
EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
EGL_NONE
};
Expand All @@ -146,7 +145,54 @@ void android_main(struct android_app* app) {
config = configs[0];
}

//TODO: perhaps dump config info for later debugging help?
{ //dump info about config for debugging purposes
EGLint value = 0;
std::string info = "Chosen config attributes:\n";
#define DO(name) \
info += " " #name ": "; \
if (EGLBoolean res = eglGetConfigAttrib(display, config, name, &value); \
res == EGL_TRUE) { \
info += std::to_string(value) + "\n"; \
} else { \
info += "(failed to get value!)\n"; \
}

DO(EGL_RED_SIZE)
DO(EGL_GREEN_SIZE)
DO(EGL_BLUE_SIZE)
DO(EGL_ALPHA_SIZE)
DO(EGL_DEPTH_SIZE)
DO(EGL_STENCIL_SIZE)
DO(EGL_ALPHA_MASK_SIZE)
DO(EGL_SAMPLE_BUFFERS)
DO(EGL_SAMPLES)
DO(EGL_BIND_TO_TEXTURE_RGB)
DO(EGL_BIND_TO_TEXTURE_RGBA)
DO(EGL_BUFFER_SIZE)
DO(EGL_COLOR_BUFFER_TYPE)
DO(EGL_CONFIG_CAVEAT)
DO(EGL_CONFIG_ID)
DO(EGL_CONFORMANT)
DO(EGL_LEVEL)
DO(EGL_LUMINANCE_SIZE)
DO(EGL_MAX_PBUFFER_WIDTH)
DO(EGL_MAX_PBUFFER_HEIGHT)
DO(EGL_MAX_PBUFFER_PIXELS)
DO(EGL_MAX_SWAP_INTERVAL)
DO(EGL_MIN_SWAP_INTERVAL)
DO(EGL_NATIVE_RENDERABLE)
DO(EGL_NATIVE_VISUAL_ID)
DO(EGL_NATIVE_VISUAL_TYPE)
DO(EGL_RENDERABLE_TYPE)
DO(EGL_SURFACE_TYPE)
DO(EGL_TRANSPARENT_TYPE)
DO(EGL_TRANSPARENT_RED_VALUE)
DO(EGL_TRANSPARENT_GREEN_VALUE)
DO(EGL_TRANSPARENT_BLUE_VALUE)

#undef DO
std::cout << info; std::cout.flush();
}

//create a surface (required when making a context current):
EGLSurface surface = EGL_NO_SURFACE;
Expand All @@ -168,6 +214,7 @@ void android_main(struct android_app* app) {
{
const EGLint attrib_list[] = {
EGL_CONTEXT_MAJOR_VERSION, 3,
EGL_CONTEXT_MINOR_VERSION, 2,
EGL_NONE
};

Expand Down

0 comments on commit 0f706df

Please sign in to comment.