blob: 2bcd1714142f32b9d65a87b226f9ce3ad2c5e692 [file] [log] [blame]
/*-------------------------------------------------------------------------
* drawElements Quality Program Tester Core
* ----------------------------------------
*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Android EGL and Vulkan platforms.
*//*--------------------------------------------------------------------*/
#include "tcuAndroidPlatform.hpp"
#include "tcuAndroidUtil.hpp"
#include "gluRenderContext.hpp"
#include "egluNativeDisplay.hpp"
#include "egluNativeWindow.hpp"
#include "egluGLContextFactory.hpp"
#include "egluUtil.hpp"
#include "eglwLibrary.hpp"
#include "eglwEnums.hpp"
#include "tcuFunctionLibrary.hpp"
#include "vkWsiPlatform.hpp"
// Assume no call translation is needed
#include <android/native_window.h>
struct egl_native_pixmap_t;
DE_STATIC_ASSERT(sizeof(eglw::EGLNativeDisplayType) == sizeof(void *));
DE_STATIC_ASSERT(sizeof(eglw::EGLNativePixmapType) == sizeof(struct egl_native_pixmap_t *));
DE_STATIC_ASSERT(sizeof(eglw::EGLNativeWindowType) == sizeof(ANativeWindow *));
namespace tcu
{
namespace Android
{
using namespace eglw;
static const eglu::NativeDisplay::Capability DISPLAY_CAPABILITIES = eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY;
static const eglu::NativeWindow::Capability WINDOW_CAPABILITIES = (eglu::NativeWindow::Capability)(
eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY | eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_PLATFORM |
eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_PLATFORM_EXTENSION | eglu::NativeWindow::CAPABILITY_SET_SURFACE_SIZE |
eglu::NativeWindow::CAPABILITY_GET_SCREEN_SIZE);
class NativeDisplay : public eglu::NativeDisplay
{
public:
NativeDisplay(void) : eglu::NativeDisplay(DISPLAY_CAPABILITIES), m_library("libEGL.so")
{
}
virtual ~NativeDisplay(void)
{
}
virtual EGLNativeDisplayType getLegacyNative(void)
{
return EGL_DEFAULT_DISPLAY;
}
virtual const eglw::Library &getLibrary(void) const
{
return m_library;
}
private:
eglw::DefaultLibrary m_library;
};
class NativeDisplayFactory : public eglu::NativeDisplayFactory
{
public:
NativeDisplayFactory(WindowRegistry &windowRegistry);
~NativeDisplayFactory(void)
{
}
virtual eglu::NativeDisplay *createDisplay(const EGLAttrib *attribList) const;
};
class NativeWindow : public eglu::NativeWindow
{
public:
NativeWindow(Window *window, int width, int height, int32_t format);
virtual ~NativeWindow(void);
virtual EGLNativeWindowType getLegacyNative(void)
{
return m_window->getNativeWindow();
}
virtual EGLNativeWindowType getPlatformExtension(void)
{
return m_window->getNativeWindow();
}
virtual EGLNativeWindowType getPlatformNative(void)
{
return m_window->getNativeWindow();
}
IVec2 getScreenSize(void) const
{
return m_window->getSize();
}
void setSurfaceSize(IVec2 size);
virtual void processEvents(void);
private:
Window *m_window;
int32_t m_format;
};
class NativeWindowFactory : public eglu::NativeWindowFactory
{
public:
NativeWindowFactory(WindowRegistry &windowRegistry);
~NativeWindowFactory(void);
virtual eglu::NativeWindow *createWindow(eglu::NativeDisplay *nativeDisplay,
const eglu::WindowParams &params) const;
virtual eglu::NativeWindow *createWindow(eglu::NativeDisplay *nativeDisplay, EGLDisplay display, EGLConfig config,
const EGLAttrib *attribList, const eglu::WindowParams &params) const;
private:
virtual eglu::NativeWindow *createWindow(const eglu::WindowParams &params, int32_t format) const;
WindowRegistry &m_windowRegistry;
};
// NativeWindow
NativeWindow::NativeWindow(Window *window, int width, int height, int32_t format)
: eglu::NativeWindow(WINDOW_CAPABILITIES)
, m_window(window)
, m_format(format)
{
// Set up buffers.
setSurfaceSize(IVec2(width, height));
}
NativeWindow::~NativeWindow(void)
{
m_window->release();
}
void NativeWindow::processEvents(void)
{
if (m_window->isPendingDestroy())
throw eglu::WindowDestroyedError("Window has been destroyed");
}
void NativeWindow::setSurfaceSize(tcu::IVec2 size)
{
m_window->setBuffersGeometry(size.x() != eglu::WindowParams::SIZE_DONT_CARE ? size.x() : 0,
size.y() != eglu::WindowParams::SIZE_DONT_CARE ? size.y() : 0, m_format);
}
// NativeWindowFactory
NativeWindowFactory::NativeWindowFactory(WindowRegistry &windowRegistry)
: eglu::NativeWindowFactory("default", "Default display", WINDOW_CAPABILITIES)
, m_windowRegistry(windowRegistry)
{
}
NativeWindowFactory::~NativeWindowFactory(void)
{
}
eglu::NativeWindow *NativeWindowFactory::createWindow(eglu::NativeDisplay *nativeDisplay,
const eglu::WindowParams &params) const
{
DE_UNREF(nativeDisplay);
return createWindow(params, WINDOW_FORMAT_RGBA_8888);
}
eglu::NativeWindow *NativeWindowFactory::createWindow(eglu::NativeDisplay *nativeDisplay, EGLDisplay display,
EGLConfig config, const EGLAttrib *attribList,
const eglu::WindowParams &params) const
{
const int32_t format =
(int32_t)eglu::getConfigAttribInt(nativeDisplay->getLibrary(), display, config, EGL_NATIVE_VISUAL_ID);
DE_UNREF(nativeDisplay && attribList);
return createWindow(params, format);
}
eglu::NativeWindow *NativeWindowFactory::createWindow(const eglu::WindowParams &params, int32_t format) const
{
Window *window = m_windowRegistry.tryAcquireWindow();
if (!window)
throw ResourceError("Native window is not available", DE_NULL, __FILE__, __LINE__);
return new NativeWindow(window, params.width, params.height, format);
}
// NativeDisplayFactory
NativeDisplayFactory::NativeDisplayFactory(WindowRegistry &windowRegistry)
: eglu::NativeDisplayFactory("default", "Default display", DISPLAY_CAPABILITIES)
{
m_nativeWindowRegistry.registerFactory(new NativeWindowFactory(windowRegistry));
}
eglu::NativeDisplay *NativeDisplayFactory::createDisplay(const EGLAttrib *attribList) const
{
DE_UNREF(attribList);
return new NativeDisplay();
}
// Vulkan
class VulkanLibrary : public vk::Library
{
public:
VulkanLibrary(void) : m_library("libvulkan.so"), m_driver(m_library)
{
}
const vk::PlatformInterface &getPlatformInterface(void) const
{
return m_driver;
}
const tcu::FunctionLibrary &getFunctionLibrary(void) const
{
return m_library;
}
private:
const tcu::DynamicFunctionLibrary m_library;
const vk::PlatformDriver m_driver;
};
DE_STATIC_ASSERT(sizeof(vk::pt::AndroidNativeWindowPtr) == sizeof(ANativeWindow *));
class VulkanWindow : public vk::wsi::AndroidWindowInterface
{
public:
VulkanWindow(tcu::Android::Window &window)
: vk::wsi::AndroidWindowInterface(vk::pt::AndroidNativeWindowPtr(window.getNativeWindow()))
, m_window(window)
{
}
void setVisible(bool visible)
{
DE_UNREF(visible);
}
void resize(const UVec2 &newSize)
{
DE_UNREF(newSize);
}
~VulkanWindow(void)
{
m_window.release();
}
private:
tcu::Android::Window &m_window;
};
class VulkanDisplay : public vk::wsi::Display
{
public:
VulkanDisplay(WindowRegistry &windowRegistry) : m_windowRegistry(windowRegistry)
{
}
vk::wsi::Window *createWindow(const Maybe<UVec2> &initialSize) const
{
Window *const window = m_windowRegistry.tryAcquireWindow();
if (window)
{
try
{
if (initialSize)
window->setBuffersGeometry((int)initialSize->x(), (int)initialSize->y(), WINDOW_FORMAT_RGBA_8888);
return new VulkanWindow(*window);
}
catch (...)
{
window->release();
throw;
}
}
else
TCU_THROW(ResourceError, "Native window is not available");
}
private:
WindowRegistry &m_windowRegistry;
};
static size_t getTotalSystemMemory(ANativeActivity *activity)
{
const size_t MiB = (size_t)(1 << 20);
try
{
const size_t totalMemory = getTotalAndroidSystemMemory(activity);
print("Device has %.2f MiB of system memory\n", static_cast<double>(totalMemory) / static_cast<double>(MiB));
return totalMemory;
}
catch (const std::exception &e)
{
// Use relatively high fallback size to encourage CDD-compliant behavior
const size_t fallbackSize = (sizeof(void *) == sizeof(uint64_t)) ? 2048 * MiB : 1024 * MiB;
print("WARNING: Failed to determine system memory size required by CDD: %s\n", e.what());
print("WARNING: Using fall-back size of %.2f MiB\n", double(fallbackSize) / double(MiB));
return fallbackSize;
}
}
// Platform
Platform::Platform(NativeActivity &activity)
: m_activity(activity)
, m_totalSystemMemory(getTotalSystemMemory(activity.getNativeActivity()))
{
m_nativeDisplayFactoryRegistry.registerFactory(new NativeDisplayFactory(m_windowRegistry));
m_contextFactoryRegistry.registerFactory(new eglu::GLContextFactory(m_nativeDisplayFactoryRegistry));
}
Platform::~Platform(void)
{
}
bool Platform::processEvents(void)
{
m_windowRegistry.garbageCollect();
return true;
}
vk::Library *Platform::createLibrary(void) const
{
return new VulkanLibrary();
}
void Platform::describePlatform(std::ostream &dst) const
{
tcu::Android::describePlatform(m_activity.getNativeActivity(), dst);
}
void Platform::getMemoryLimits(tcu::PlatformMemoryLimits &limits) const
{
// Worst-case estimates
const size_t MiB = (size_t)(1 << 20);
const size_t baseMemUsage = 400 * MiB;
const double safeUsageRatio = 0.25;
limits.totalSystemMemory =
de::max((size_t)(double(int64_t(m_totalSystemMemory) - int64_t(baseMemUsage)) * safeUsageRatio), 16 * MiB);
// Assume UMA architecture
limits.totalDeviceLocalMemory = 0;
// Reasonable worst-case estimates
limits.deviceMemoryAllocationGranularity = 64 * 1024;
limits.devicePageSize = 4096;
limits.devicePageTableEntrySize = 8;
limits.devicePageTableHierarchyLevels = 3;
}
vk::wsi::Display *Platform::createWsiDisplay(vk::wsi::Type wsiType) const
{
if (wsiType == vk::wsi::TYPE_ANDROID)
return new VulkanDisplay(const_cast<WindowRegistry &>(m_windowRegistry));
else
TCU_THROW(NotSupportedError, "WSI type not supported on Android");
}
bool Platform::hasDisplay(vk::wsi::Type wsiType) const
{
if (wsiType == vk::wsi::TYPE_ANDROID)
return true;
return false;
}
} // namespace Android
} // namespace tcu