diff --git a/include/neural-graphics-primitives/openxr_hmd.h b/include/neural-graphics-primitives/openxr_hmd.h
index ee442ef9aa5f07abeae2c2f78a06f3d376c59916..ac6cacab5f212653baf36ecd762a9f81e0444263 100644
--- a/include/neural-graphics-primitives/openxr_hmd.h
+++ b/include/neural-graphics-primitives/openxr_hmd.h
@@ -47,6 +47,21 @@
 
 NGP_NAMESPACE_BEGIN
 
+enum class EnvironmentBlendMode {
+	Opaque = XR_ENVIRONMENT_BLEND_MODE_OPAQUE,
+	Additive = XR_ENVIRONMENT_BLEND_MODE_ADDITIVE,
+	AlphaBlend = XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND,
+};
+
+inline std::string to_string(EnvironmentBlendMode mode) {
+	switch (mode) {
+		case EnvironmentBlendMode::Opaque: return "Opaque";
+		case EnvironmentBlendMode::Additive: return "Additive";
+		case EnvironmentBlendMode::AlphaBlend: return "Blend";
+		default: throw std::runtime_error{"Invalid blend mode."};
+	}
+}
+
 class OpenXRHMD {
 public:
 	enum class ControlFlow {
@@ -108,6 +123,22 @@ public:
 	// must be called for each begin_frame
 	void end_frame(FrameInfoPtr frame_info, float znear, float zfar);
 
+	void set_environment_blend_mode(EnvironmentBlendMode mode) {
+		m_environment_blend_mode = mode;
+	}
+
+	EnvironmentBlendMode environment_blend_mode() const {
+		return m_environment_blend_mode;
+	}
+
+	const std::vector<EnvironmentBlendMode>& supported_environment_blend_modes() const {
+		return m_supported_environment_blend_modes;
+	}
+
+	const std::string& supported_environment_blend_modes_string() const {
+		return m_supported_environment_blend_modes_string;
+	}
+
 	// if true call begin_frame and end_frame - does not imply visibility
 	bool must_run_frame_loop() const {
 		return
@@ -161,8 +192,9 @@ private:
 	XrViewConfigurationType m_view_configuration_type = {};
 	XrViewConfigurationProperties m_view_configuration_properties = {XR_TYPE_VIEW_CONFIGURATION_PROPERTIES};
 	std::vector<XrViewConfigurationView> m_view_configuration_views;
-	std::vector<XrEnvironmentBlendMode> m_environment_blend_modes;
-	XrEnvironmentBlendMode m_environment_blend_mode = {XR_ENVIRONMENT_BLEND_MODE_OPAQUE};
+	std::vector<EnvironmentBlendMode> m_supported_environment_blend_modes;
+	std::string m_supported_environment_blend_modes_string;
+	EnvironmentBlendMode m_environment_blend_mode = EnvironmentBlendMode::Opaque;
 
 	// actions
 	std::array<XrPath, 2> m_hand_paths;
diff --git a/src/openxr_hmd.cu b/src/openxr_hmd.cu
index b7d2cd4e8e4c8bd5d4b418b7797dbd805c064991..0befdfce511a95c0fd6b2badf53dce88db4d1d38 100644
--- a/src/openxr_hmd.cu
+++ b/src/openxr_hmd.cu
@@ -425,34 +425,39 @@ void OpenXRHMD::init_check_for_xr_blend_mode() {
 	// enumerate environment blend modes
 	uint32_t size;
 	XR_CHECK_THROW(xrEnumerateEnvironmentBlendModes(m_instance, m_system_id, m_view_configuration_type, 0, &size, nullptr));
-	m_environment_blend_modes.resize(size);
+	std::vector<XrEnvironmentBlendMode> supported_blend_modes(size);
 	XR_CHECK_THROW(xrEnumerateEnvironmentBlendModes(
 		m_instance,
 		m_system_id,
 		m_view_configuration_type,
 		size,
 		&size,
-		m_environment_blend_modes.data()
+		supported_blend_modes.data()
 	));
 
+	if (supported_blend_modes.empty()) {
+		throw std::runtime_error{"No OpenXR environment blend modes found"};
+	}
+
 	if (m_print_environment_blend_modes) {
-		tlog::info() << fmt::format("Environment Blend Modes ({}):", m_environment_blend_modes.size());
+		tlog::info() << fmt::format("Environment Blend Modes ({}):", supported_blend_modes.size());
 	}
 
-	bool found = false;
-	for (const auto& m : m_environment_blend_modes) {
+	m_supported_environment_blend_modes.resize(size);
+	m_supported_environment_blend_modes_string = "";
+	for (size_t i = 0; i < supported_blend_modes.size(); ++i) {
 		if (m_print_environment_blend_modes) {
-			tlog::info() << fmt::format("\t{}", XrEnumStr(m));
+			tlog::info() << fmt::format("\t{}", XrEnumStr(supported_blend_modes[i]));
 		}
 
-		if (m == m_environment_blend_mode) {
-			found = true;
-		}
+		auto b = (EnvironmentBlendMode)supported_blend_modes[i];
+		m_supported_environment_blend_modes[i] = b;
+		m_supported_environment_blend_modes_string += to_string(b) + "\0";
 	}
 
-	if (!found) {
-		throw std::runtime_error{fmt::format("OpenXR environment blend mode {} not found", XrEnumStr(m_environment_blend_mode))};
-	}
+	m_supported_environment_blend_modes_string += "\0";
+
+	m_environment_blend_mode = m_supported_environment_blend_modes.front();
 }
 
 void OpenXRHMD::init_xr_actions() {
@@ -1236,7 +1241,7 @@ void OpenXRHMD::end_frame(FrameInfoPtr frame_info, float znear, float zfar) {
 
 	XrFrameEndInfo frame_end_info{XR_TYPE_FRAME_END_INFO};
 	frame_end_info.displayTime = m_frame_state.predictedDisplayTime;
-	frame_end_info.environmentBlendMode = m_environment_blend_mode;
+	frame_end_info.environmentBlendMode = (XrEnvironmentBlendMode)m_environment_blend_mode;
 	frame_end_info.layerCount = (uint32_t)layers.size();
 	frame_end_info.layers = layers.data();
 	XR_CHECK_THROW(xrEndFrame(m_session, &frame_end_info));
diff --git a/src/testbed.cu b/src/testbed.cu
index c212f96de628af14f5f0886ae8e1f83e4eb77957..9d322d6e7f058e52e29edccf3ac0eb77b4e7bef1 100644
--- a/src/testbed.cu
+++ b/src/testbed.cu
@@ -925,16 +925,32 @@ void Testbed::imgui() {
 					ImGui::OpenPopup("Error");
 				}
 			}
-		} else if (ImGui::TreeNodeEx("VR/AR settings", ImGuiTreeNodeFlags_DefaultOpen)) {
-			if (m_devices.size() > 1 && m_testbed_mode == ETestbedMode::Nerf) {
-				ImGui::Checkbox("Multi-GPU rendering (one per eye)", &m_use_aux_devices);
-			}
+		} else {
+			if (ImGui::Button("Disconnect from VR/AR headset")) {
+				m_hmd.reset();
+				m_vr_frame_info = nullptr;
+				m_render_transparency_as_checkerboard = false;
+			} else if (ImGui::TreeNodeEx("VR/AR settings", ImGuiTreeNodeFlags_DefaultOpen)) {
+				static int blend_mode_idx = 0;
+				const auto& supported_blend_modes = m_hmd->supported_environment_blend_modes();
+				if (supported_blend_modes.size() > 1) {
+					if (ImGui::Combo("Environment blend mode", &blend_mode_idx, m_hmd->supported_environment_blend_modes_string().c_str())) {
+						auto b = m_hmd->supported_environment_blend_modes().at(blend_mode_idx);
+						m_hmd->set_environment_blend_mode(b);
+						m_render_transparency_as_checkerboard = (b == EnvironmentBlendMode::Opaque);
+					}
+				}
 
-			accum_reset |= ImGui::Checkbox("Foveated rendering", &m_foveated_rendering) && !m_dlss;
-			if (m_foveated_rendering) {
-				accum_reset |= ImGui::SliderFloat("Maximum foveation", &m_foveated_rendering_max_scaling, 1.0f, 16.0f, "%.01f", ImGuiSliderFlags_Logarithmic | ImGuiSliderFlags_NoRoundToFormat) && !m_dlss;
+				if (m_devices.size() > 1 && m_testbed_mode == ETestbedMode::Nerf) {
+					ImGui::Checkbox("Multi-GPU rendering (one per eye)", &m_use_aux_devices);
+				}
+
+				accum_reset |= ImGui::Checkbox("Foveated rendering", &m_foveated_rendering) && !m_dlss;
+				if (m_foveated_rendering) {
+					accum_reset |= ImGui::SliderFloat("Maximum foveation", &m_foveated_rendering_max_scaling, 1.0f, 16.0f, "%.01f", ImGuiSliderFlags_Logarithmic | ImGuiSliderFlags_NoRoundToFormat) && !m_dlss;
+				}
+				ImGui::TreePop();
 			}
-			ImGui::TreePop();
 		}
 
 		ImGui::Checkbox("Render", &m_render);
@@ -3144,7 +3160,7 @@ bool Testbed::frame() {
 		ImGui::EndFrame();
 	}
 
-	if (m_vr_frame_info) {
+	if (m_hmd && m_vr_frame_info) {
 		// If HMD is visible to the user, splat rendered images to the HMD
 		if (m_hmd->is_visible()) {
 			size_t n_views = std::min(m_views.size(), m_vr_frame_info->views.size());
@@ -4186,7 +4202,7 @@ void Testbed::render_frame_epilogue(
 		Matrix<float, 3, 4> checkerboard_transform = Matrix<float, 3, 4>::Identity();
 
 #if NGP_GUI
-		if (m_vr_frame_info && !m_vr_frame_info->views.empty()) {
+		if (m_hmd && m_vr_frame_info && !m_vr_frame_info->views.empty()) {
 			checkerboard_transform = m_vr_frame_info->views[0].pose;
 		}
 #endif
@@ -4266,7 +4282,7 @@ void Testbed::render_frame_epilogue(
 
 #if NGP_GUI
 	// If in VR, indicate the hand position and render transparent background
-	if (m_vr_frame_info) {
+	if (m_hmd && m_vr_frame_info) {
 		auto& hands = m_vr_frame_info->hands;
 
 		auto res = render_buffer.out_resolution();