Implement renderer instance which composes multiple layers into a window
This commit is contained in:
parent
d4b4a795c3
commit
8018942323
21 changed files with 723 additions and 118 deletions
|
|
@ -105,6 +105,9 @@ set(SOURCES
|
||||||
anbox/graphics/gl_renderer_server.cpp
|
anbox/graphics/gl_renderer_server.cpp
|
||||||
anbox/graphics/density.h
|
anbox/graphics/density.h
|
||||||
anbox/graphics/rect.cpp
|
anbox/graphics/rect.cpp
|
||||||
|
anbox/graphics/layer_composer.cpp
|
||||||
|
anbox/graphics/program_family.cpp
|
||||||
|
anbox/graphics/primitives.h
|
||||||
|
|
||||||
anbox/graphics/emugl/ColorBuffer.cpp
|
anbox/graphics/emugl/ColorBuffer.cpp
|
||||||
anbox/graphics/emugl/DisplayManager.cpp
|
anbox/graphics/emugl/DisplayManager.cpp
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory)
|
||||||
|
|
||||||
auto window_manager = std::make_shared<wm::Manager>(policy);
|
auto window_manager = std::make_shared<wm::Manager>(policy);
|
||||||
|
|
||||||
auto renderer = std::make_shared<graphics::GLRendererServer>();
|
auto renderer = std::make_shared<graphics::GLRendererServer>(window_manager);
|
||||||
renderer->start();
|
renderer->start();
|
||||||
|
|
||||||
// Socket which will be used by the qemud service inside the Android
|
// Socket which will be used by the qemud service inside the Android
|
||||||
|
|
|
||||||
|
|
@ -376,11 +376,6 @@ bool ColorBuffer::bindToRenderbuffer() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ColorBuffer::post(float rotation, float dx, float dy) {
|
|
||||||
// NOTE: Do not call m_helper->setupContext() here!
|
|
||||||
return m_helper->getTextureDraw()->draw(m_resizer->update(m_tex));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ColorBuffer::readback(unsigned char* img) {
|
void ColorBuffer::readback(unsigned char* img) {
|
||||||
ScopedHelperContext context(m_helper);
|
ScopedHelperContext context(m_helper);
|
||||||
if (!context.isOk()) {
|
if (!context.isOk()) {
|
||||||
|
|
@ -392,3 +387,8 @@ void ColorBuffer::readback(unsigned char* img) {
|
||||||
unbindFbo();
|
unbindFbo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ColorBuffer::bind() {
|
||||||
|
const auto id = m_resizer->update(m_tex);
|
||||||
|
s_gles2.glBindTexture(GL_TEXTURE_2D, id);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -108,15 +108,6 @@ public:
|
||||||
GLenum p_type,
|
GLenum p_type,
|
||||||
void *pixels);
|
void *pixels);
|
||||||
|
|
||||||
// Draw a ColorBuffer instance, i.e. blit it to the current guest
|
|
||||||
// framebuffer object / window surface. This doesn't display anything.
|
|
||||||
bool draw();
|
|
||||||
|
|
||||||
// Post this ColorBuffer to the host native sub-window.
|
|
||||||
// |rotation| is the rotation angle in degrees, clockwise in the GL
|
|
||||||
// coordinate space.
|
|
||||||
bool post(float rotation, float dx, float dy);
|
|
||||||
|
|
||||||
// Bind the current context's EGL_TEXTURE_2D texture to this ColorBuffer's
|
// Bind the current context's EGL_TEXTURE_2D texture to this ColorBuffer's
|
||||||
// EGLImage. This is intended to implement glEGLImageTargetTexture2DOES()
|
// EGLImage. This is intended to implement glEGLImageTargetTexture2DOES()
|
||||||
// for all GLES versions.
|
// for all GLES versions.
|
||||||
|
|
@ -136,6 +127,7 @@ public:
|
||||||
// |img| must be a buffer large enough (i.e. width * height * 4).
|
// |img| must be a buffer large enough (i.e. width * height * 4).
|
||||||
void readback(unsigned char* img);
|
void readback(unsigned char* img);
|
||||||
|
|
||||||
|
void bind();
|
||||||
private:
|
private:
|
||||||
ColorBuffer(); // no default constructor.
|
ColorBuffer(); // no default constructor.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,19 @@
|
||||||
|
|
||||||
#include "OpenGLESDispatch/EGLDispatch.h"
|
#include "OpenGLESDispatch/EGLDispatch.h"
|
||||||
|
|
||||||
|
#include "anbox/graphics/layer_composer.h"
|
||||||
|
#include "anbox/logger.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
static const GLint rendererVersion = 1;
|
static const GLint rendererVersion = 1;
|
||||||
|
static std::shared_ptr<anbox::graphics::LayerComposer> composer;
|
||||||
|
|
||||||
|
void registerLayerComposer(const std::shared_ptr<anbox::graphics::LayerComposer> &c)
|
||||||
|
{
|
||||||
|
composer = c;
|
||||||
|
}
|
||||||
|
|
||||||
static GLint rcGetRendererVersion()
|
static GLint rcGetRendererVersion()
|
||||||
{
|
{
|
||||||
|
|
@ -305,12 +314,7 @@ static EGLint rcMakeCurrent(uint32_t context,
|
||||||
|
|
||||||
static void rcFBPost(uint32_t colorBuffer)
|
static void rcFBPost(uint32_t colorBuffer)
|
||||||
{
|
{
|
||||||
Renderer *fb = Renderer::get();
|
WARNING("Not implemented");
|
||||||
if (!fb) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fb->post(nullptr, colorBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rcFBSetSwapInterval(EGLint interval)
|
static void rcFBSetSwapInterval(EGLint interval)
|
||||||
|
|
@ -425,15 +429,31 @@ int rcGetDisplayVsyncPeriod(uint32_t display_id) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<Renderable> frame_layers;
|
||||||
|
|
||||||
|
bool is_layer_blacklisted(const std::string &name) {
|
||||||
|
static std::vector<std::string> blacklist = {
|
||||||
|
"Sprite",
|
||||||
|
};
|
||||||
|
return std::find(blacklist.begin(), blacklist.end(), name) != blacklist.end();
|
||||||
|
}
|
||||||
|
|
||||||
void rcPostLayer(const char *name, uint32_t color_buffer,
|
void rcPostLayer(const char *name, uint32_t color_buffer,
|
||||||
int32_t sourceCropLeft, int32_t sourceCropTop,
|
int32_t sourceCropLeft, int32_t sourceCropTop,
|
||||||
int32_t sourceCropRight, int32_t sourceCropBottom,
|
int32_t sourceCropRight, int32_t sourceCropBottom,
|
||||||
int32_t displayFrameLeft, int32_t displayFrameTop,
|
int32_t displayFrameLeft, int32_t displayFrameTop,
|
||||||
int32_t displayFrameRight, int32_t displayFrameBottom) {
|
int32_t displayFrameRight, int32_t displayFrameBottom)
|
||||||
|
{
|
||||||
|
Renderable r{name, color_buffer, {displayFrameLeft, displayFrameTop, displayFrameRight, displayFrameBottom}};
|
||||||
|
frame_layers.push_back(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rcPostAllLayersDone() {
|
void rcPostAllLayersDone()
|
||||||
|
{
|
||||||
|
if (composer)
|
||||||
|
composer->submit_layers(frame_layers);
|
||||||
|
|
||||||
|
frame_layers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void initRenderControlContext(renderControl_decoder_context_t *dec)
|
void initRenderControlContext(renderControl_decoder_context_t *dec)
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,15 @@
|
||||||
|
|
||||||
#include "renderControl_dec.h"
|
#include "renderControl_dec.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace anbox {
|
||||||
|
namespace graphics {
|
||||||
|
class LayerComposer;
|
||||||
|
} // namespace graphics
|
||||||
|
} // namespace anbox
|
||||||
|
|
||||||
void initRenderControlContext(renderControl_decoder_context_t *dec);
|
void initRenderControlContext(renderControl_decoder_context_t *dec);
|
||||||
|
void registerLayerComposer(const std::shared_ptr<anbox::graphics::LayerComposer> &c);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,16 @@
|
||||||
|
|
||||||
#include "Renderable.h"
|
#include "Renderable.h"
|
||||||
|
|
||||||
Renderable::Renderable(const std::uint32_t &buffer,
|
Renderable::Renderable(const std::string &name,
|
||||||
const anbox::graphics::Rect &screen_position) :
|
const std::uint32_t &buffer,
|
||||||
|
const anbox::graphics::Rect &screen_position,
|
||||||
|
const glm::mat4 &transformation,
|
||||||
|
const float &alpha) :
|
||||||
|
name_(name),
|
||||||
buffer_(buffer),
|
buffer_(buffer),
|
||||||
screen_position_(screen_position)
|
screen_position_(screen_position),
|
||||||
|
transformation_(transformation),
|
||||||
|
alpha_(alpha)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,6 +33,11 @@ Renderable::~Renderable()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Renderable::name() const
|
||||||
|
{
|
||||||
|
return name_;
|
||||||
|
}
|
||||||
|
|
||||||
std::uint32_t Renderable::buffer() const
|
std::uint32_t Renderable::buffer() const
|
||||||
{
|
{
|
||||||
return buffer_;
|
return buffer_;
|
||||||
|
|
@ -36,3 +47,13 @@ anbox::graphics::Rect Renderable::screen_position() const
|
||||||
{
|
{
|
||||||
return screen_position_;
|
return screen_position_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::mat4 Renderable::transformation() const
|
||||||
|
{
|
||||||
|
return transformation_;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Renderable::alpha() const
|
||||||
|
{
|
||||||
|
return alpha_;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,23 +19,35 @@
|
||||||
|
|
||||||
#include "anbox/graphics/rect.h"
|
#include "anbox/graphics/rect.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
class Renderable
|
class Renderable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Renderable(const std::uint32_t &buffer,
|
Renderable(const std::string &name,
|
||||||
const anbox::graphics::Rect &screen_position);
|
const std::uint32_t &buffer,
|
||||||
|
const anbox::graphics::Rect &screen_position,
|
||||||
|
const glm::mat4 &transformation = {},
|
||||||
|
const float &alpha = 1.0f);
|
||||||
~Renderable();
|
~Renderable();
|
||||||
|
|
||||||
|
std::string name() const;
|
||||||
std::uint32_t buffer() const;
|
std::uint32_t buffer() const;
|
||||||
anbox::graphics::Rect screen_position() const;
|
anbox::graphics::Rect screen_position() const;
|
||||||
|
glm::mat4 transformation() const;
|
||||||
|
float alpha() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::string name_;
|
||||||
std::uint32_t buffer_;
|
std::uint32_t buffer_;
|
||||||
anbox::graphics::Rect screen_position_;
|
anbox::graphics::Rect screen_position_;
|
||||||
|
glm::mat4 transformation_;
|
||||||
|
float alpha_;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Renderable> RenderableList;
|
typedef std::vector<Renderable> RenderableList;
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,14 @@
|
||||||
|
|
||||||
#include "emugl/common/logging.h"
|
#include "emugl/common/logging.h"
|
||||||
|
|
||||||
|
#include "anbox/logger.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtx/transform.hpp>
|
||||||
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Helper class to call the bind_locked() / unbind_locked() properly.
|
// Helper class to call the bind_locked() / unbind_locked() properly.
|
||||||
|
|
@ -415,6 +421,9 @@ bool Renderer::initialize(EGLNativeDisplayType nativeDisplay)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fb->m_defaultProgram = fb->m_family.add_program(vshader, defaultFShader);
|
||||||
|
fb->m_alphaProgram = fb->m_family.add_program(vshader, alphaFShader);
|
||||||
|
|
||||||
// release the FB context
|
// release the FB context
|
||||||
bind.release();
|
bind.release();
|
||||||
|
|
||||||
|
|
@ -426,6 +435,19 @@ bool Renderer::initialize(EGLNativeDisplayType nativeDisplay)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Renderer::Program::Program(GLuint program_id)
|
||||||
|
{
|
||||||
|
id = program_id;
|
||||||
|
position_attr = s_gles2.glGetAttribLocation(id, "position");
|
||||||
|
texcoord_attr = s_gles2.glGetAttribLocation(id, "texcoord");
|
||||||
|
tex_uniform = s_gles2.glGetUniformLocation(id, "tex");
|
||||||
|
centre_uniform = s_gles2.glGetUniformLocation(id, "centre");
|
||||||
|
display_transform_uniform = s_gles2.glGetUniformLocation(id, "display_transform");
|
||||||
|
transform_uniform = s_gles2.glGetUniformLocation(id, "transform");
|
||||||
|
screen_to_gl_coords_uniform = s_gles2.glGetUniformLocation(id, "screen_to_gl_coords");
|
||||||
|
alpha_uniform = s_gles2.glGetUniformLocation(id, "alpha");
|
||||||
|
}
|
||||||
|
|
||||||
Renderer::Renderer() :
|
Renderer::Renderer() :
|
||||||
m_configs(NULL),
|
m_configs(NULL),
|
||||||
m_eglDisplay(EGL_NO_DISPLAY),
|
m_eglDisplay(EGL_NO_DISPLAY),
|
||||||
|
|
@ -455,6 +477,9 @@ Renderer::~Renderer() {
|
||||||
struct RendererWindow {
|
struct RendererWindow {
|
||||||
EGLNativeWindowType native_window = 0;
|
EGLNativeWindowType native_window = 0;
|
||||||
EGLSurface surface = EGL_NO_SURFACE;
|
EGLSurface surface = EGL_NO_SURFACE;
|
||||||
|
anbox::graphics::Rect viewport;
|
||||||
|
glm::mat4 screen_to_gl_coords;
|
||||||
|
glm::mat4 display_transform;
|
||||||
};
|
};
|
||||||
|
|
||||||
RendererWindow* Renderer::createNativeWindow(EGLNativeWindowType native_window)
|
RendererWindow* Renderer::createNativeWindow(EGLNativeWindowType native_window)
|
||||||
|
|
@ -480,7 +505,6 @@ RendererWindow* Renderer::createNativeWindow(EGLNativeWindowType native_window)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// s_gles2.glViewport(0, 0, width, height);
|
|
||||||
s_gles2.glClear(GL_COLOR_BUFFER_BIT |
|
s_gles2.glClear(GL_COLOR_BUFFER_BIT |
|
||||||
GL_DEPTH_BUFFER_BIT |
|
GL_DEPTH_BUFFER_BIT |
|
||||||
GL_STENCIL_BUFFER_BIT);
|
GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
@ -954,68 +978,172 @@ bool Renderer::unbind_locked()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Renderer::post(RendererWindow *window, HandleType p_colorbuffer, bool needLock)
|
const GLchar* const Renderer::vshader =
|
||||||
{
|
{
|
||||||
if (!window)
|
"attribute vec3 position;\n"
|
||||||
return false;
|
"attribute vec2 texcoord;\n"
|
||||||
|
"uniform mat4 screen_to_gl_coords;\n"
|
||||||
|
"uniform mat4 display_transform;\n"
|
||||||
|
"uniform mat4 transform;\n"
|
||||||
|
"uniform vec2 centre;\n"
|
||||||
|
"varying vec2 v_texcoord;\n"
|
||||||
|
"void main() {\n"
|
||||||
|
" vec4 mid = vec4(centre, 0.0, 0.0);\n"
|
||||||
|
" vec4 transformed = (transform * (vec4(position, 1.0) - mid)) + mid;\n"
|
||||||
|
" gl_Position = display_transform * screen_to_gl_coords * transformed;\n"
|
||||||
|
" v_texcoord = texcoord;\n"
|
||||||
|
"}\n"
|
||||||
|
};
|
||||||
|
|
||||||
if (needLock)
|
const GLchar* const Renderer::alphaFShader =
|
||||||
m_lock.lock();
|
{
|
||||||
|
"precision mediump float;\n"
|
||||||
|
"uniform sampler2D tex;\n"
|
||||||
|
"uniform float alpha;\n"
|
||||||
|
"varying vec2 v_texcoord;\n"
|
||||||
|
"void main() {\n"
|
||||||
|
" vec4 frag = texture2D(tex, v_texcoord);\n"
|
||||||
|
" gl_FragColor = alpha*frag;\n"
|
||||||
|
"}\n"
|
||||||
|
};
|
||||||
|
|
||||||
bool ret;
|
const GLchar* const Renderer::defaultFShader =
|
||||||
|
{ // This is the fastest fragment shader. Use it when you can.
|
||||||
|
"precision mediump float;\n"
|
||||||
|
"uniform sampler2D tex;\n"
|
||||||
|
"varying vec2 v_texcoord;\n"
|
||||||
|
"void main() {\n"
|
||||||
|
" gl_FragColor = texture2D(tex, v_texcoord);\n"
|
||||||
|
"}\n"
|
||||||
|
};
|
||||||
|
|
||||||
ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
|
void Renderer::setupViewport(RendererWindow *window, const anbox::graphics::Rect &rect)
|
||||||
if (c == m_colorbuffers.end())
|
{
|
||||||
goto EXIT;
|
/*
|
||||||
|
* Here we provide a 3D perspective projection with a default 30 degrees
|
||||||
|
* vertical field of view. This projection matrix is carefully designed
|
||||||
|
* such that any vertices at depth z=0 will fit the screen coordinates. So
|
||||||
|
* client texels will fit screen pixels perfectly as long as the surface is
|
||||||
|
* at depth zero. But if you want to do anything fancy, you can also choose
|
||||||
|
* a different depth and it will appear to come out of or go into the
|
||||||
|
* screen.
|
||||||
|
*/
|
||||||
|
window->screen_to_gl_coords = glm::translate(glm::mat4(1.0f), glm::vec3{-1.0f, 1.0f, 0.0f});
|
||||||
|
|
||||||
m_lastPostedColorBuffer = p_colorbuffer;
|
/*
|
||||||
|
* Perspective division is one thing that can't be done in a matrix
|
||||||
|
* multiplication. It happens after the matrix multiplications. GL just
|
||||||
|
* scales {x,y} by 1/w. So modify the final part of the projection matrix
|
||||||
|
* to set w ([3]) to be the incoming z coordinate ([2]).
|
||||||
|
*/
|
||||||
|
window->screen_to_gl_coords[2][3] = -1.0f;
|
||||||
|
|
||||||
if (!bindWindow_locked(window))
|
float const vertical_fov_degrees = 30.0f;
|
||||||
goto EXIT;
|
float const near =
|
||||||
|
(rect.height() / 2.0f) /
|
||||||
|
std::tan((vertical_fov_degrees * M_PI / 180.0f) / 2.0f);
|
||||||
|
float const far = -near;
|
||||||
|
|
||||||
#if 0
|
window->screen_to_gl_coords = glm::scale(window->screen_to_gl_coords,
|
||||||
if (window->needViewportUpdate) {
|
glm::vec3{2.0f / rect.width(),
|
||||||
s_gles2.glViewport(0, 0, window->width, window->height);
|
-2.0f / rect.height(),
|
||||||
window->needViewportUpdate = false;
|
2.0f / (near - far)});
|
||||||
}
|
window->screen_to_gl_coords = glm::translate(window->screen_to_gl_coords,
|
||||||
#endif
|
glm::vec3{-rect.left(),
|
||||||
|
-rect.top(),
|
||||||
|
0.0f});
|
||||||
|
|
||||||
s_gles2.glClearColor(0.0, 0.0, 1.0, 0.0);
|
window->viewport = rect;
|
||||||
s_gles2.glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
|
|
||||||
ret = (*c).second.cb->post(0.0f, 0, 0);
|
|
||||||
if (ret) {
|
|
||||||
s_egl.eglSwapBuffers(m_eglDisplay, window->surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
// restore previous binding
|
|
||||||
unbind_locked();
|
|
||||||
|
|
||||||
//
|
|
||||||
// output FPS statistics
|
|
||||||
//
|
|
||||||
if (m_fpsStats) {
|
|
||||||
long long currTime = GetCurrentTimeMS();
|
|
||||||
m_statsNumFrames++;
|
|
||||||
if (currTime - m_statsStartTime >= 1000) {
|
|
||||||
float dt = (float)(currTime - m_statsStartTime) / 1000.0f;
|
|
||||||
printf("FPS: %5.3f\n", (float)m_statsNumFrames / dt);
|
|
||||||
m_statsStartTime = currTime;
|
|
||||||
m_statsNumFrames = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EXIT:
|
|
||||||
if (!ret)
|
|
||||||
printf("post: FAILED\n");
|
|
||||||
|
|
||||||
if (needLock) {
|
|
||||||
m_lock.unlock();
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Renderer::draw(EGLNativeWindowType native_window, const RenderableList &renderables)
|
void Renderer::tessellate(std::vector<anbox::graphics::Primitive>& primitives,
|
||||||
|
const anbox::graphics::Rect &buf_size,
|
||||||
|
const Renderable &renderable)
|
||||||
|
{
|
||||||
|
auto rect = renderable.screen_position();
|
||||||
|
GLfloat left = rect.left();
|
||||||
|
GLfloat right = rect.right();
|
||||||
|
GLfloat top = rect.top();
|
||||||
|
GLfloat bottom = rect.bottom();
|
||||||
|
|
||||||
|
anbox::graphics::Primitive rectangle;
|
||||||
|
rectangle.tex_id = 0;
|
||||||
|
rectangle.type = GL_TRIANGLE_STRIP;
|
||||||
|
|
||||||
|
GLfloat tex_right = static_cast<GLfloat>(rect.width()) /
|
||||||
|
buf_size.width();
|
||||||
|
GLfloat tex_bottom = static_cast<GLfloat>(rect.height()) /
|
||||||
|
buf_size.height();
|
||||||
|
|
||||||
|
auto& vertices = rectangle.vertices;
|
||||||
|
vertices[0] = {{left, top, 0.0f}, {0.0f, 0.0f}};
|
||||||
|
vertices[1] = {{left, bottom, 0.0f}, {0.0f, tex_bottom}};
|
||||||
|
vertices[2] = {{right, top, 0.0f}, {tex_right, 0.0f}};
|
||||||
|
vertices[3] = {{right, bottom, 0.0f}, {tex_right, tex_bottom}};
|
||||||
|
|
||||||
|
primitives.resize(1);
|
||||||
|
primitives[0] = rectangle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::draw(RendererWindow *window, const Renderable &renderable, const Program &prog)
|
||||||
|
{
|
||||||
|
const auto &color_buffer = m_colorbuffers.find(renderable.buffer());
|
||||||
|
if (color_buffer == m_colorbuffers.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto &cb = color_buffer->second.cb;
|
||||||
|
|
||||||
|
s_gles2.glUseProgram(prog.id);
|
||||||
|
s_gles2.glUniform1i(prog.tex_uniform, 0);
|
||||||
|
s_gles2.glUniformMatrix4fv(prog.display_transform_uniform, 1, GL_FALSE,
|
||||||
|
glm::value_ptr(window->display_transform));
|
||||||
|
s_gles2.glUniformMatrix4fv(prog.screen_to_gl_coords_uniform, 1, GL_FALSE,
|
||||||
|
glm::value_ptr(window->screen_to_gl_coords));
|
||||||
|
|
||||||
|
s_gles2.glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
auto const& rect = renderable.screen_position();
|
||||||
|
GLfloat centrex = rect.left() +
|
||||||
|
rect.width() / 2.0f;
|
||||||
|
GLfloat centrey = rect.top() +
|
||||||
|
rect.height() / 2.0f;
|
||||||
|
s_gles2.glUniform2f(prog.centre_uniform, centrex, centrey);
|
||||||
|
|
||||||
|
s_gles2.glUniformMatrix4fv(prog.transform_uniform, 1, GL_FALSE,
|
||||||
|
glm::value_ptr(renderable.transformation()));
|
||||||
|
|
||||||
|
if (prog.alpha_uniform >= 0)
|
||||||
|
s_gles2.glUniform1f(prog.alpha_uniform, renderable.alpha());
|
||||||
|
|
||||||
|
s_gles2.glEnableVertexAttribArray(prog.position_attr);
|
||||||
|
s_gles2.glEnableVertexAttribArray(prog.texcoord_attr);
|
||||||
|
|
||||||
|
m_primitives.clear();
|
||||||
|
tessellate(m_primitives, {cb->getWidth(), cb->getHeight()}, renderable);
|
||||||
|
|
||||||
|
for (auto const& p : m_primitives)
|
||||||
|
{
|
||||||
|
cb->bind();
|
||||||
|
|
||||||
|
s_gles2.glVertexAttribPointer(prog.position_attr, 3, GL_FLOAT,
|
||||||
|
GL_FALSE, sizeof(anbox::graphics::Vertex),
|
||||||
|
&p.vertices[0].position);
|
||||||
|
s_gles2.glVertexAttribPointer(prog.texcoord_attr, 2, GL_FLOAT,
|
||||||
|
GL_FALSE, sizeof(anbox::graphics::Vertex),
|
||||||
|
&p.vertices[0].texcoord);
|
||||||
|
|
||||||
|
s_gles2.glEnable(GL_BLEND);
|
||||||
|
s_gles2.glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA,
|
||||||
|
GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
s_gles2.glDrawArrays(p.type, 0, p.nvertices);
|
||||||
|
}
|
||||||
|
|
||||||
|
s_gles2.glDisableVertexAttribArray(prog.texcoord_attr);
|
||||||
|
s_gles2.glDisableVertexAttribArray(prog.position_attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Renderer::draw(EGLNativeWindowType native_window, const anbox::graphics::Rect &window_frame, const RenderableList &renderables)
|
||||||
{
|
{
|
||||||
auto w = m_nativeWindows.find(native_window);
|
auto w = m_nativeWindows.find(native_window);
|
||||||
if (w == m_nativeWindows.end())
|
if (w == m_nativeWindows.end())
|
||||||
|
|
@ -1027,18 +1155,13 @@ bool Renderer::draw(EGLNativeWindowType native_window, const RenderableList &ren
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_gles2.glClearColor(0.0, 0.0, 1.0, 0.0);
|
setupViewport(w->second, window_frame);
|
||||||
|
s_gles2.glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||||
|
s_gles2.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||||
s_gles2.glClear(GL_COLOR_BUFFER_BIT);
|
s_gles2.glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
for (const auto &renderable : renderables)
|
for (const auto &r : renderables)
|
||||||
{
|
draw(w->second, r, r.alpha() < 1.0f ? m_alphaProgram : m_defaultProgram);
|
||||||
const auto &color_buffer = m_colorbuffers.find(renderable.buffer());
|
|
||||||
if (color_buffer == m_colorbuffers.end())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
color_buffer->second.cb->post(0.0f,
|
|
||||||
renderable.screen_position().left(), renderable.screen_position().top());
|
|
||||||
}
|
|
||||||
|
|
||||||
s_egl.eglSwapBuffers(m_eglDisplay, w->second->surface);
|
s_egl.eglSwapBuffers(m_eglDisplay, w->second->surface);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,9 @@
|
||||||
|
|
||||||
#include "Renderable.h"
|
#include "Renderable.h"
|
||||||
|
|
||||||
|
#include "anbox/graphics/program_family.h"
|
||||||
|
#include "anbox/graphics/primitives.h"
|
||||||
|
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
@ -229,14 +232,7 @@ public:
|
||||||
int x, int y, int width, int height,
|
int x, int y, int width, int height,
|
||||||
GLenum format, GLenum type, void *pixels);
|
GLenum format, GLenum type, void *pixels);
|
||||||
|
|
||||||
// Display the content of a given ColorBuffer into the framebuffer's
|
bool draw(EGLNativeWindowType native_window, const anbox::graphics::Rect &window_frame, const RenderableList &renderables);
|
||||||
// sub-window. |p_colorbuffer| is a handle value.
|
|
||||||
// |needLock| is used to indicate whether the operation requires
|
|
||||||
// acquiring/releasing the FrameBuffer instance's lock. It should be
|
|
||||||
// false only when called internally.
|
|
||||||
bool post(RendererWindow *window, HandleType p_colorbuffer, bool needLock = true);
|
|
||||||
|
|
||||||
bool draw(EGLNativeWindowType native_window, const RenderableList &renderables);
|
|
||||||
|
|
||||||
// Return the host EGLDisplay used by this instance.
|
// Return the host EGLDisplay used by this instance.
|
||||||
EGLDisplay getDisplay() const { return m_eglDisplay; }
|
EGLDisplay getDisplay() const { return m_eglDisplay; }
|
||||||
|
|
@ -259,6 +255,13 @@ private:
|
||||||
|
|
||||||
bool bindWindow_locked(RendererWindow *window);
|
bool bindWindow_locked(RendererWindow *window);
|
||||||
|
|
||||||
|
void setupViewport(RendererWindow *window, const anbox::graphics::Rect &rect);
|
||||||
|
struct Program;
|
||||||
|
void draw(RendererWindow *window, const Renderable &renderable, const Program &prog);
|
||||||
|
void tessellate(std::vector<anbox::graphics::Primitive>& primitives,
|
||||||
|
const anbox::graphics::Rect &buf_size,
|
||||||
|
const Renderable &renderable);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Renderer *s_renderer;
|
static Renderer *s_renderer;
|
||||||
static HandleType s_nextHandle;
|
static HandleType s_nextHandle;
|
||||||
|
|
@ -292,5 +295,30 @@ private:
|
||||||
const char* m_glVersion;
|
const char* m_glVersion;
|
||||||
|
|
||||||
std::map<EGLNativeWindowType,RendererWindow*> m_nativeWindows;
|
std::map<EGLNativeWindowType,RendererWindow*> m_nativeWindows;
|
||||||
|
|
||||||
|
anbox::graphics::ProgramFamily m_family;
|
||||||
|
struct Program
|
||||||
|
{
|
||||||
|
GLuint id = 0;
|
||||||
|
GLint tex_uniform = -1;
|
||||||
|
GLint position_attr = -1;
|
||||||
|
GLint texcoord_attr = -1;
|
||||||
|
GLint centre_uniform = -1;
|
||||||
|
GLint display_transform_uniform = -1;
|
||||||
|
GLint transform_uniform = -1;
|
||||||
|
GLint screen_to_gl_coords_uniform = -1;
|
||||||
|
GLint alpha_uniform = -1;
|
||||||
|
mutable long long last_used_frameno = 0;
|
||||||
|
|
||||||
|
Program(GLuint program_id);
|
||||||
|
Program() {}
|
||||||
|
};
|
||||||
|
Program m_defaultProgram, m_alphaProgram;
|
||||||
|
|
||||||
|
std::vector<anbox::graphics::Primitive> m_primitives;
|
||||||
|
|
||||||
|
static const GLchar* const vshader;
|
||||||
|
static const GLchar* const defaultFShader;
|
||||||
|
static const GLchar* const alphaFShader;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@
|
||||||
|
|
||||||
#include "anbox/logger.h"
|
#include "anbox/logger.h"
|
||||||
#include "anbox/graphics/gl_renderer_server.h"
|
#include "anbox/graphics/gl_renderer_server.h"
|
||||||
|
#include "anbox/graphics/layer_composer.h"
|
||||||
|
#include "anbox/graphics/emugl/RenderControl.h"
|
||||||
|
#include "anbox/wm/manager.h"
|
||||||
|
|
||||||
#include "OpenglRender/render_api.h"
|
#include "OpenglRender/render_api.h"
|
||||||
|
|
||||||
|
|
@ -26,7 +29,9 @@
|
||||||
|
|
||||||
namespace anbox {
|
namespace anbox {
|
||||||
namespace graphics {
|
namespace graphics {
|
||||||
GLRendererServer::GLRendererServer()
|
GLRendererServer::GLRendererServer(const std::shared_ptr<wm::Manager> &wm) :
|
||||||
|
wm_(wm),
|
||||||
|
composer_(std::make_shared<LayerComposer>(wm))
|
||||||
{
|
{
|
||||||
|
|
||||||
if (utils::is_env_set("USE_HOST_GLES")) {
|
if (utils::is_env_set("USE_HOST_GLES")) {
|
||||||
|
|
@ -43,6 +48,8 @@ GLRendererServer::GLRendererServer()
|
||||||
|
|
||||||
if (!initLibrary())
|
if (!initLibrary())
|
||||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize OpenGL renderer"));
|
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize OpenGL renderer"));
|
||||||
|
|
||||||
|
registerLayerComposer(composer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLRendererServer::~GLRendererServer() {
|
GLRendererServer::~GLRendererServer() {
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,14 @@ namespace anbox {
|
||||||
namespace input {
|
namespace input {
|
||||||
class Manager;
|
class Manager;
|
||||||
} // namespace input
|
} // namespace input
|
||||||
|
namespace wm {
|
||||||
|
class Manager;
|
||||||
|
} // namespace wm
|
||||||
namespace graphics {
|
namespace graphics {
|
||||||
class WindowCreator;
|
class LayerComposer;
|
||||||
class GLRendererServer {
|
class GLRendererServer {
|
||||||
public:
|
public:
|
||||||
GLRendererServer();
|
GLRendererServer(const std::shared_ptr<wm::Manager> &wm);
|
||||||
~GLRendererServer();
|
~GLRendererServer();
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
|
|
@ -38,6 +41,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string socket_path_;
|
std::string socket_path_;
|
||||||
|
std::shared_ptr<wm::Manager> wm_;
|
||||||
|
std::shared_ptr<LayerComposer> composer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace graphics
|
} // namespace graphics
|
||||||
|
|
|
||||||
63
src/anbox/graphics/layer_composer.cpp
Normal file
63
src/anbox/graphics/layer_composer.cpp
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 3, as published
|
||||||
|
* by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranties of
|
||||||
|
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "anbox/graphics/layer_composer.h"
|
||||||
|
#include "anbox/graphics/emugl/Renderer.h"
|
||||||
|
#include "anbox/wm/manager.h"
|
||||||
|
#include "anbox/logger.h"
|
||||||
|
|
||||||
|
namespace anbox {
|
||||||
|
namespace graphics {
|
||||||
|
LayerComposer::LayerComposer(const std::shared_ptr<wm::Manager> &wm) :
|
||||||
|
wm_(wm)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LayerComposer::~LayerComposer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayerComposer::submit_layers(const RenderableList &renderables)
|
||||||
|
{
|
||||||
|
std::map<std::shared_ptr<wm::Window>,RenderableList> win_layers;
|
||||||
|
for (const auto &renderable : renderables)
|
||||||
|
{
|
||||||
|
// Ignore all surfaces which are not meant for a task
|
||||||
|
if (!utils::string_starts_with(renderable.name(), "org.anbox.surface."))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
wm::Task::Id task_id = 0;
|
||||||
|
if (sscanf(renderable.name().c_str(), "org.anbox.surface.%d", &task_id) != 1 || !task_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto w = wm_->find_window_for_task(task_id);
|
||||||
|
if (!w)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (win_layers.find(w) == win_layers.end()) {
|
||||||
|
win_layers.insert({w, {renderable}});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
win_layers[w].push_back(renderable);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &w : win_layers)
|
||||||
|
Renderer::get()->draw(w.first->native_handle(), w.first->state().frame(), w.second);
|
||||||
|
}
|
||||||
|
} // namespace graphics
|
||||||
|
} // namespace anbox
|
||||||
43
src/anbox/graphics/layer_composer.h
Normal file
43
src/anbox/graphics/layer_composer.h
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 3, as published
|
||||||
|
* by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranties of
|
||||||
|
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ANBOX_GRAPHICS_LAYER_COMPOSER_H_
|
||||||
|
#define ANBOX_GRAPHICS_LAYER_COMPOSER_H_
|
||||||
|
|
||||||
|
#include "anbox/graphics/emugl/Renderable.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace anbox {
|
||||||
|
namespace wm {
|
||||||
|
class Manager;
|
||||||
|
} // namespace wm
|
||||||
|
namespace graphics {
|
||||||
|
class LayerComposer {
|
||||||
|
public:
|
||||||
|
LayerComposer(const std::shared_ptr<wm::Manager> &wm);
|
||||||
|
~LayerComposer();
|
||||||
|
|
||||||
|
void submit_layers(const RenderableList &renderables);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<wm::Manager> wm_;
|
||||||
|
};
|
||||||
|
} // namespace graphics
|
||||||
|
} // namespace anbox
|
||||||
|
|
||||||
|
#endif
|
||||||
52
src/anbox/graphics/primitives.h
Normal file
52
src/anbox/graphics/primitives.h
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2014 Canonical Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
|
||||||
|
* Kevin DuBois <kevin.dubois@canonical.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ANBOX_GRAPHICS_PRIMITIVES_H_
|
||||||
|
#define ANBOX_GRAPHICS_PRIMITIVES_H_
|
||||||
|
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
|
|
||||||
|
namespace anbox {
|
||||||
|
namespace graphics {
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
GLfloat position[3];
|
||||||
|
GLfloat texcoord[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Primitive
|
||||||
|
{
|
||||||
|
enum {max_vertices = 4};
|
||||||
|
|
||||||
|
Primitive()
|
||||||
|
: type(GL_TRIANGLE_FAN), nvertices(4)
|
||||||
|
{
|
||||||
|
// Default is a quad. Just need to assign vertices[] and tex_id.
|
||||||
|
}
|
||||||
|
|
||||||
|
GLenum type; // GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES etc
|
||||||
|
GLuint tex_id; // GL texture ID (or 0 to represent the surface itself)
|
||||||
|
int nvertices;
|
||||||
|
Vertex vertices[max_vertices];
|
||||||
|
};
|
||||||
|
} // namespace graphics
|
||||||
|
} // namespace anbox
|
||||||
|
|
||||||
|
#endif
|
||||||
107
src/anbox/graphics/program_family.cpp
Normal file
107
src/anbox/graphics/program_family.cpp
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2015 Canonical Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "anbox/graphics/program_family.h"
|
||||||
|
|
||||||
|
#include "anbox/graphics/emugl/DispatchTables.h"
|
||||||
|
|
||||||
|
namespace anbox {
|
||||||
|
namespace graphics {
|
||||||
|
void ProgramFamily::Shader::init(GLenum type, const GLchar* src)
|
||||||
|
{
|
||||||
|
if (!id)
|
||||||
|
{
|
||||||
|
id = s_gles2.glCreateShader(type);
|
||||||
|
if (id)
|
||||||
|
{
|
||||||
|
s_gles2.glShaderSource(id, 1, &src, NULL);
|
||||||
|
s_gles2.glCompileShader(id);
|
||||||
|
GLint ok;
|
||||||
|
s_gles2.glGetShaderiv(id, GL_COMPILE_STATUS, &ok);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
GLchar log[1024];
|
||||||
|
s_gles2.glGetShaderInfoLog(id, sizeof log - 1, NULL, log);
|
||||||
|
log[sizeof log - 1] = '\0';
|
||||||
|
s_gles2.glDeleteShader(id);
|
||||||
|
id = 0;
|
||||||
|
throw std::runtime_error(std::string("Compile failed: ")+
|
||||||
|
log + " for:\n" + src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgramFamily::~ProgramFamily() noexcept
|
||||||
|
{
|
||||||
|
// shader and program lifetimes are managed manually, so that we don't
|
||||||
|
// need any reference counting or to worry about how many copy constructions
|
||||||
|
// might have been followed by destructor calls during container resizes.
|
||||||
|
|
||||||
|
for (auto& p : program)
|
||||||
|
{
|
||||||
|
if (p.second.id)
|
||||||
|
s_gles2.glDeleteProgram(p.second.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& v : vshader)
|
||||||
|
{
|
||||||
|
if (v.second.id)
|
||||||
|
s_gles2.glDeleteShader(v.second.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& f : fshader)
|
||||||
|
{
|
||||||
|
if (f.second.id)
|
||||||
|
s_gles2.glDeleteShader(f.second.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint ProgramFamily::add_program(const GLchar* const vshader_src,
|
||||||
|
const GLchar* const fshader_src)
|
||||||
|
{
|
||||||
|
auto& v = vshader[vshader_src];
|
||||||
|
if (!v.id) v.init(GL_VERTEX_SHADER, vshader_src);
|
||||||
|
|
||||||
|
auto& f = fshader[fshader_src];
|
||||||
|
if (!f.id) f.init(GL_FRAGMENT_SHADER, fshader_src);
|
||||||
|
|
||||||
|
auto& p = program[{v.id, f.id}];
|
||||||
|
if (!p.id)
|
||||||
|
{
|
||||||
|
p.id = s_gles2.glCreateProgram();
|
||||||
|
s_gles2.glAttachShader(p.id, v.id);
|
||||||
|
s_gles2.glAttachShader(p.id, f.id);
|
||||||
|
s_gles2.glLinkProgram(p.id);
|
||||||
|
GLint ok;
|
||||||
|
s_gles2.glGetProgramiv(p.id, GL_LINK_STATUS, &ok);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
GLchar log[1024];
|
||||||
|
s_gles2.glGetProgramInfoLog(p.id, sizeof log - 1, NULL, log);
|
||||||
|
log[sizeof log - 1] = '\0';
|
||||||
|
s_gles2.glDeleteShader(p.id);
|
||||||
|
p.id = 0;
|
||||||
|
throw std::runtime_error(std::string("Link failed: ")+log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.id;
|
||||||
|
}
|
||||||
|
} // namespace graphics
|
||||||
|
} // namespace anbox
|
||||||
68
src/anbox/graphics/program_family.h
Normal file
68
src/anbox/graphics/program_family.h
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2015 Canonical Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ANBOX_GRAPHICS_PROGRAM_FAMILY_H_
|
||||||
|
#define ANBOX_GRAPHICS_PROGRAM_FAMILY_H_
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <map>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
|
|
||||||
|
namespace anbox {
|
||||||
|
namespace graphics {
|
||||||
|
/**
|
||||||
|
* ProgramFamily represents a set of GLSL programs that are closely
|
||||||
|
* related. Programs which point to the same shader source strings will be
|
||||||
|
* made to share the same compiled shader objects.
|
||||||
|
* A secondary intention is that this class may be extended to allow the
|
||||||
|
* different programs within the family to share common patterns of uniform
|
||||||
|
* usage too.
|
||||||
|
*/
|
||||||
|
class ProgramFamily
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProgramFamily() = default;
|
||||||
|
ProgramFamily(ProgramFamily const&) = delete;
|
||||||
|
ProgramFamily& operator=(ProgramFamily const&) = delete;
|
||||||
|
~ProgramFamily() noexcept;
|
||||||
|
|
||||||
|
GLuint add_program(const GLchar* const static_vshader_src,
|
||||||
|
const GLchar* const static_fshader_src);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Shader
|
||||||
|
{
|
||||||
|
GLuint id = 0;
|
||||||
|
void init(GLenum type, const GLchar* src);
|
||||||
|
};
|
||||||
|
typedef std::unordered_map<const GLchar*, Shader> ShaderMap;
|
||||||
|
ShaderMap vshader, fshader;
|
||||||
|
|
||||||
|
typedef std::pair<GLuint, GLuint> ShaderPair;
|
||||||
|
struct Program
|
||||||
|
{
|
||||||
|
GLuint id = 0;
|
||||||
|
};
|
||||||
|
std::map<ShaderPair, Program> program;
|
||||||
|
};
|
||||||
|
} // namespace graphics
|
||||||
|
} // namespace anbox
|
||||||
|
|
||||||
|
#endif // MIR_RENDERER_GL_PROGRAM_FAMILY_H_
|
||||||
|
|
@ -19,6 +19,8 @@
|
||||||
#include "anbox/wm/platform_policy.h"
|
#include "anbox/wm/platform_policy.h"
|
||||||
#include "anbox/logger.h"
|
#include "anbox/logger.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace anbox {
|
namespace anbox {
|
||||||
namespace wm {
|
namespace wm {
|
||||||
Manager::Manager(const std::shared_ptr<PlatformPolicy> &platform) :
|
Manager::Manager(const std::shared_ptr<PlatformPolicy> &platform) :
|
||||||
|
|
@ -31,6 +33,8 @@ Manager::~Manager() {
|
||||||
void Manager::apply_window_state_update(const WindowState::List &updated,
|
void Manager::apply_window_state_update(const WindowState::List &updated,
|
||||||
const WindowState::List &removed)
|
const WindowState::List &removed)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> l(mutex_);
|
||||||
|
|
||||||
DEBUG("updated %d removed %d", updated.size(), removed.size());
|
DEBUG("updated %d removed %d", updated.size(), removed.size());
|
||||||
|
|
||||||
// Base on the update we get from the Android WindowManagerService we will create
|
// Base on the update we get from the Android WindowManagerService we will create
|
||||||
|
|
@ -38,30 +42,46 @@ void Manager::apply_window_state_update(const WindowState::List &updated,
|
||||||
// from SurfaceFlinger will be mapped later into those windows and eventually
|
// from SurfaceFlinger will be mapped later into those windows and eventually
|
||||||
// composited there via GLES (e.g. for popups, ..)
|
// composited there via GLES (e.g. for popups, ..)
|
||||||
|
|
||||||
for (const auto &window : updated) {
|
for (const auto &window : updated)
|
||||||
|
{
|
||||||
auto w = windows_.find(window.task());
|
auto w = windows_.find(window.task());
|
||||||
if (w != windows_.end()) {
|
if (w != windows_.end())
|
||||||
DEBUG("Found existing window for task %d", window.task());
|
{
|
||||||
w->second->update_state(window);
|
w->second->update_state(window);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
DEBUG("Found new window for task %d", window.task());
|
|
||||||
auto platform_window = platform_->create_window(window);
|
auto platform_window = platform_->create_window(window);
|
||||||
|
platform_window->ref();
|
||||||
platform_window->attach();
|
platform_window->attach();
|
||||||
windows_.insert({window.task(), platform_window});
|
windows_.insert({window.task(), platform_window});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &window : removed) {
|
for (const auto &window : removed)
|
||||||
|
{
|
||||||
auto w = windows_.find(window.task());
|
auto w = windows_.find(window.task());
|
||||||
if (w == windows_.end()) {
|
if (w == windows_.end())
|
||||||
WARNING("Got remove request for window we don't know about (task id %d)", window.task());
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
w->second->unref();
|
||||||
|
if (!w->second->still_used())
|
||||||
|
{
|
||||||
|
auto platform_window = w->second;
|
||||||
|
platform_window->release();
|
||||||
|
windows_.erase(w);
|
||||||
}
|
}
|
||||||
DEBUG("Removing window for task %d", window.task());
|
|
||||||
auto platform_window = w->second;
|
|
||||||
platform_window->release();
|
|
||||||
windows_.erase(w);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Window> Manager::find_window_for_task(const Task::Id &task)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(mutex_);
|
||||||
|
|
||||||
|
for (const auto &w : windows_)
|
||||||
|
{
|
||||||
|
if (w.second->state().task() == task)
|
||||||
|
return w.second;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
} // namespace wm
|
} // namespace wm
|
||||||
} // namespace anbox
|
} // namespace anbox
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
namespace anbox {
|
namespace anbox {
|
||||||
namespace wm {
|
namespace wm {
|
||||||
|
|
@ -35,7 +36,10 @@ public:
|
||||||
void apply_window_state_update(const WindowState::List &updated,
|
void apply_window_state_update(const WindowState::List &updated,
|
||||||
const WindowState::List &removed);
|
const WindowState::List &removed);
|
||||||
|
|
||||||
|
std::shared_ptr<Window> find_window_for_task(const Task::Id &task);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::mutex mutex_;
|
||||||
std::shared_ptr<PlatformPolicy> platform_;
|
std::shared_ptr<PlatformPolicy> platform_;
|
||||||
std::map<Task::Id, std::shared_ptr<Window>> windows_;
|
std::map<Task::Id, std::shared_ptr<Window>> windows_;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -17,18 +17,24 @@
|
||||||
|
|
||||||
#include "anbox/wm/window.h"
|
#include "anbox/wm/window.h"
|
||||||
#include "anbox/graphics/emugl/Renderer.h"
|
#include "anbox/graphics/emugl/Renderer.h"
|
||||||
|
#include "anbox/logger.h"
|
||||||
|
|
||||||
namespace anbox {
|
namespace anbox {
|
||||||
namespace wm {
|
namespace wm {
|
||||||
Window::Window(const WindowState &state) :
|
Window::Window(const WindowState &state) :
|
||||||
state_(state) {
|
state_(state),
|
||||||
|
refcount_(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Window::~Window() {
|
Window::~Window() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::update_state(const WindowState &state) {
|
void Window::update_state(const WindowState &new_state) {
|
||||||
state_ = state;
|
state_ = new_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowState Window::state() const {
|
||||||
|
return state_;
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLNativeWindowType Window::native_handle() const {
|
EGLNativeWindowType Window::native_handle() const {
|
||||||
|
|
@ -42,6 +48,23 @@ bool Window::attach() {
|
||||||
void Window::release() {
|
void Window::release() {
|
||||||
Renderer::get()->destroyNativeWindow(native_handle());
|
Renderer::get()->destroyNativeWindow(native_handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::ref() {
|
||||||
|
refcount_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::unref() {
|
||||||
|
if (refcount_ == 0) {
|
||||||
|
WARNING("reference count is out of sync");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
refcount_--;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Window::still_used() const {
|
||||||
|
return refcount_ > 0;
|
||||||
|
}
|
||||||
} // namespace wm
|
} // namespace wm
|
||||||
} // namespace anbox
|
} // namespace anbox
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,12 +42,16 @@ class Window
|
||||||
public:
|
public:
|
||||||
typedef std::vector<Window> List;
|
typedef std::vector<Window> List;
|
||||||
|
|
||||||
Window(const WindowState &state);
|
Window(const WindowState &new_state);
|
||||||
virtual ~Window();
|
virtual ~Window();
|
||||||
|
|
||||||
bool attach();
|
bool attach();
|
||||||
void release();
|
void release();
|
||||||
|
|
||||||
|
void ref();
|
||||||
|
void unref();
|
||||||
|
bool still_used() const;
|
||||||
|
|
||||||
void update_state(const WindowState &state);
|
void update_state(const WindowState &state);
|
||||||
|
|
||||||
virtual EGLNativeWindowType native_handle() const;
|
virtual EGLNativeWindowType native_handle() const;
|
||||||
|
|
@ -55,6 +59,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WindowState state_;
|
WindowState state_;
|
||||||
|
std::uint32_t refcount_;
|
||||||
};
|
};
|
||||||
} // namespace wm
|
} // namespace wm
|
||||||
} // namespace anbox
|
} // namespace anbox
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue