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/density.h
|
||||
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/DisplayManager.cpp
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory)
|
|||
|
||||
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();
|
||||
|
||||
// Socket which will be used by the qemud service inside the Android
|
||||
|
|
|
|||
|
|
@ -376,11 +376,6 @@ bool ColorBuffer::bindToRenderbuffer() {
|
|||
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) {
|
||||
ScopedHelperContext context(m_helper);
|
||||
if (!context.isOk()) {
|
||||
|
|
@ -392,3 +387,8 @@ void ColorBuffer::readback(unsigned char* img) {
|
|||
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,
|
||||
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
|
||||
// EGLImage. This is intended to implement glEGLImageTargetTexture2DOES()
|
||||
// for all GLES versions.
|
||||
|
|
@ -136,6 +127,7 @@ public:
|
|||
// |img| must be a buffer large enough (i.e. width * height * 4).
|
||||
void readback(unsigned char* img);
|
||||
|
||||
void bind();
|
||||
private:
|
||||
ColorBuffer(); // no default constructor.
|
||||
|
||||
|
|
|
|||
|
|
@ -24,10 +24,19 @@
|
|||
|
||||
#include "OpenGLESDispatch/EGLDispatch.h"
|
||||
|
||||
#include "anbox/graphics/layer_composer.h"
|
||||
#include "anbox/logger.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
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()
|
||||
{
|
||||
|
|
@ -305,12 +314,7 @@ static EGLint rcMakeCurrent(uint32_t context,
|
|||
|
||||
static void rcFBPost(uint32_t colorBuffer)
|
||||
{
|
||||
Renderer *fb = Renderer::get();
|
||||
if (!fb) {
|
||||
return;
|
||||
}
|
||||
|
||||
fb->post(nullptr, colorBuffer);
|
||||
WARNING("Not implemented");
|
||||
}
|
||||
|
||||
static void rcFBSetSwapInterval(EGLint interval)
|
||||
|
|
@ -425,15 +429,31 @@ int rcGetDisplayVsyncPeriod(uint32_t display_id) {
|
|||
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,
|
||||
int32_t sourceCropLeft, int32_t sourceCropTop,
|
||||
int32_t sourceCropRight, int32_t sourceCropBottom,
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,15 @@
|
|||
|
||||
#include "renderControl_dec.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace anbox {
|
||||
namespace graphics {
|
||||
class LayerComposer;
|
||||
} // namespace graphics
|
||||
} // namespace anbox
|
||||
|
||||
void initRenderControlContext(renderControl_decoder_context_t *dec);
|
||||
void registerLayerComposer(const std::shared_ptr<anbox::graphics::LayerComposer> &c);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,10 +16,16 @@
|
|||
|
||||
#include "Renderable.h"
|
||||
|
||||
Renderable::Renderable(const std::uint32_t &buffer,
|
||||
const anbox::graphics::Rect &screen_position) :
|
||||
Renderable::Renderable(const std::string &name,
|
||||
const std::uint32_t &buffer,
|
||||
const anbox::graphics::Rect &screen_position,
|
||||
const glm::mat4 &transformation,
|
||||
const float &alpha) :
|
||||
name_(name),
|
||||
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
|
||||
{
|
||||
return buffer_;
|
||||
|
|
@ -36,3 +47,13 @@ anbox::graphics::Rect Renderable::screen_position() const
|
|||
{
|
||||
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 <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class Renderable
|
||||
{
|
||||
public:
|
||||
Renderable(const std::uint32_t &buffer,
|
||||
const anbox::graphics::Rect &screen_position);
|
||||
Renderable(const std::string &name,
|
||||
const std::uint32_t &buffer,
|
||||
const anbox::graphics::Rect &screen_position,
|
||||
const glm::mat4 &transformation = {},
|
||||
const float &alpha = 1.0f);
|
||||
~Renderable();
|
||||
|
||||
std::string name() const;
|
||||
std::uint32_t buffer() const;
|
||||
anbox::graphics::Rect screen_position() const;
|
||||
glm::mat4 transformation() const;
|
||||
float alpha() const;
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::uint32_t buffer_;
|
||||
anbox::graphics::Rect screen_position_;
|
||||
glm::mat4 transformation_;
|
||||
float alpha_;
|
||||
};
|
||||
|
||||
typedef std::vector<Renderable> RenderableList;
|
||||
|
|
|
|||
|
|
@ -25,8 +25,14 @@
|
|||
|
||||
#include "emugl/common/logging.h"
|
||||
|
||||
#include "anbox/logger.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
// Helper class to call the bind_locked() / unbind_locked() properly.
|
||||
|
|
@ -415,6 +421,9 @@ bool Renderer::initialize(EGLNativeDisplayType nativeDisplay)
|
|||
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
|
||||
bind.release();
|
||||
|
||||
|
|
@ -426,6 +435,19 @@ bool Renderer::initialize(EGLNativeDisplayType nativeDisplay)
|
|||
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() :
|
||||
m_configs(NULL),
|
||||
m_eglDisplay(EGL_NO_DISPLAY),
|
||||
|
|
@ -455,6 +477,9 @@ Renderer::~Renderer() {
|
|||
struct RendererWindow {
|
||||
EGLNativeWindowType native_window = 0;
|
||||
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)
|
||||
|
|
@ -480,7 +505,6 @@ RendererWindow* Renderer::createNativeWindow(EGLNativeWindowType native_window)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// s_gles2.glViewport(0, 0, width, height);
|
||||
s_gles2.glClear(GL_COLOR_BUFFER_BIT |
|
||||
GL_DEPTH_BUFFER_BIT |
|
||||
GL_STENCIL_BUFFER_BIT);
|
||||
|
|
@ -954,68 +978,172 @@ bool Renderer::unbind_locked()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Renderer::post(RendererWindow *window, HandleType p_colorbuffer, bool needLock)
|
||||
const GLchar* const Renderer::vshader =
|
||||
{
|
||||
if (!window)
|
||||
return false;
|
||||
"attribute vec3 position;\n"
|
||||
"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)
|
||||
m_lock.lock();
|
||||
const GLchar* const Renderer::alphaFShader =
|
||||
{
|
||||
"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) );
|
||||
if (c == m_colorbuffers.end())
|
||||
goto EXIT;
|
||||
void Renderer::setupViewport(RendererWindow *window, const anbox::graphics::Rect &rect)
|
||||
{
|
||||
/*
|
||||
* 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))
|
||||
goto EXIT;
|
||||
float const vertical_fov_degrees = 30.0f;
|
||||
float const near =
|
||||
(rect.height() / 2.0f) /
|
||||
std::tan((vertical_fov_degrees * M_PI / 180.0f) / 2.0f);
|
||||
float const far = -near;
|
||||
|
||||
#if 0
|
||||
if (window->needViewportUpdate) {
|
||||
s_gles2.glViewport(0, 0, window->width, window->height);
|
||||
window->needViewportUpdate = false;
|
||||
}
|
||||
#endif
|
||||
window->screen_to_gl_coords = glm::scale(window->screen_to_gl_coords,
|
||||
glm::vec3{2.0f / rect.width(),
|
||||
-2.0f / rect.height(),
|
||||
2.0f / (near - far)});
|
||||
window->screen_to_gl_coords = glm::translate(window->screen_to_gl_coords,
|
||||
glm::vec3{-rect.left(),
|
||||
-rect.top(),
|
||||
0.0f});
|
||||
|
||||
s_gles2.glClearColor(0.0, 0.0, 1.0, 0.0);
|
||||
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;
|
||||
window->viewport = rect;
|
||||
}
|
||||
|
||||
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);
|
||||
if (w == m_nativeWindows.end())
|
||||
|
|
@ -1027,18 +1155,13 @@ bool Renderer::draw(EGLNativeWindowType native_window, const RenderableList &ren
|
|||
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);
|
||||
|
||||
for (const auto &renderable : renderables)
|
||||
{
|
||||
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());
|
||||
}
|
||||
for (const auto &r : renderables)
|
||||
draw(w->second, r, r.alpha() < 1.0f ? m_alphaProgram : m_defaultProgram);
|
||||
|
||||
s_egl.eglSwapBuffers(m_eglDisplay, w->second->surface);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@
|
|||
|
||||
#include "Renderable.h"
|
||||
|
||||
#include "anbox/graphics/program_family.h"
|
||||
#include "anbox/graphics/primitives.h"
|
||||
|
||||
#include <EGL/egl.h>
|
||||
|
||||
#include <map>
|
||||
|
|
@ -229,14 +232,7 @@ public:
|
|||
int x, int y, int width, int height,
|
||||
GLenum format, GLenum type, void *pixels);
|
||||
|
||||
// Display the content of a given ColorBuffer into the framebuffer's
|
||||
// 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);
|
||||
bool draw(EGLNativeWindowType native_window, const anbox::graphics::Rect &window_frame, const RenderableList &renderables);
|
||||
|
||||
// Return the host EGLDisplay used by this instance.
|
||||
EGLDisplay getDisplay() const { return m_eglDisplay; }
|
||||
|
|
@ -259,6 +255,13 @@ private:
|
|||
|
||||
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:
|
||||
static Renderer *s_renderer;
|
||||
static HandleType s_nextHandle;
|
||||
|
|
@ -292,5 +295,30 @@ private:
|
|||
const char* m_glVersion;
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
#include "anbox/logger.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"
|
||||
|
||||
|
|
@ -26,7 +29,9 @@
|
|||
|
||||
namespace anbox {
|
||||
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")) {
|
||||
|
|
@ -43,6 +48,8 @@ GLRendererServer::GLRendererServer()
|
|||
|
||||
if (!initLibrary())
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize OpenGL renderer"));
|
||||
|
||||
registerLayerComposer(composer_);
|
||||
}
|
||||
|
||||
GLRendererServer::~GLRendererServer() {
|
||||
|
|
|
|||
|
|
@ -25,11 +25,14 @@ namespace anbox {
|
|||
namespace input {
|
||||
class Manager;
|
||||
} // namespace input
|
||||
namespace wm {
|
||||
class Manager;
|
||||
} // namespace wm
|
||||
namespace graphics {
|
||||
class WindowCreator;
|
||||
class LayerComposer;
|
||||
class GLRendererServer {
|
||||
public:
|
||||
GLRendererServer();
|
||||
GLRendererServer(const std::shared_ptr<wm::Manager> &wm);
|
||||
~GLRendererServer();
|
||||
|
||||
void start();
|
||||
|
|
@ -38,6 +41,8 @@ public:
|
|||
|
||||
private:
|
||||
std::string socket_path_;
|
||||
std::shared_ptr<wm::Manager> wm_;
|
||||
std::shared_ptr<LayerComposer> composer_;
|
||||
};
|
||||
|
||||
} // 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/logger.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace anbox {
|
||||
namespace wm {
|
||||
Manager::Manager(const std::shared_ptr<PlatformPolicy> &platform) :
|
||||
|
|
@ -31,6 +33,8 @@ Manager::~Manager() {
|
|||
void Manager::apply_window_state_update(const WindowState::List &updated,
|
||||
const WindowState::List &removed)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(mutex_);
|
||||
|
||||
DEBUG("updated %d removed %d", updated.size(), removed.size());
|
||||
|
||||
// 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
|
||||
// composited there via GLES (e.g. for popups, ..)
|
||||
|
||||
for (const auto &window : updated) {
|
||||
for (const auto &window : updated)
|
||||
{
|
||||
auto w = windows_.find(window.task());
|
||||
if (w != windows_.end()) {
|
||||
DEBUG("Found existing window for task %d", window.task());
|
||||
if (w != windows_.end())
|
||||
{
|
||||
w->second->update_state(window);
|
||||
continue;
|
||||
}
|
||||
DEBUG("Found new window for task %d", window.task());
|
||||
auto platform_window = platform_->create_window(window);
|
||||
platform_window->ref();
|
||||
platform_window->attach();
|
||||
windows_.insert({window.task(), platform_window});
|
||||
}
|
||||
|
||||
for (const auto &window : removed) {
|
||||
for (const auto &window : removed)
|
||||
{
|
||||
auto w = windows_.find(window.task());
|
||||
if (w == windows_.end()) {
|
||||
WARNING("Got remove request for window we don't know about (task id %d)", window.task());
|
||||
if (w == windows_.end())
|
||||
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 anbox
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
namespace anbox {
|
||||
namespace wm {
|
||||
|
|
@ -35,7 +36,10 @@ public:
|
|||
void apply_window_state_update(const WindowState::List &updated,
|
||||
const WindowState::List &removed);
|
||||
|
||||
std::shared_ptr<Window> find_window_for_task(const Task::Id &task);
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::shared_ptr<PlatformPolicy> platform_;
|
||||
std::map<Task::Id, std::shared_ptr<Window>> windows_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,18 +17,24 @@
|
|||
|
||||
#include "anbox/wm/window.h"
|
||||
#include "anbox/graphics/emugl/Renderer.h"
|
||||
#include "anbox/logger.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace wm {
|
||||
Window::Window(const WindowState &state) :
|
||||
state_(state) {
|
||||
state_(state),
|
||||
refcount_(0) {
|
||||
}
|
||||
|
||||
Window::~Window() {
|
||||
}
|
||||
|
||||
void Window::update_state(const WindowState &state) {
|
||||
state_ = state;
|
||||
void Window::update_state(const WindowState &new_state) {
|
||||
state_ = new_state;
|
||||
}
|
||||
|
||||
WindowState Window::state() const {
|
||||
return state_;
|
||||
}
|
||||
|
||||
EGLNativeWindowType Window::native_handle() const {
|
||||
|
|
@ -42,6 +48,23 @@ bool Window::attach() {
|
|||
void Window::release() {
|
||||
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 anbox
|
||||
|
||||
|
|
|
|||
|
|
@ -42,12 +42,16 @@ class Window
|
|||
public:
|
||||
typedef std::vector<Window> List;
|
||||
|
||||
Window(const WindowState &state);
|
||||
Window(const WindowState &new_state);
|
||||
virtual ~Window();
|
||||
|
||||
bool attach();
|
||||
void release();
|
||||
|
||||
void ref();
|
||||
void unref();
|
||||
bool still_used() const;
|
||||
|
||||
void update_state(const WindowState &state);
|
||||
|
||||
virtual EGLNativeWindowType native_handle() const;
|
||||
|
|
@ -55,6 +59,7 @@ public:
|
|||
|
||||
private:
|
||||
WindowState state_;
|
||||
std::uint32_t refcount_;
|
||||
};
|
||||
} // namespace wm
|
||||
} // namespace anbox
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue