Panda3D
eglGraphicsBuffer.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file eglGraphicsBuffer.cxx
10 * @author rdb
11 * @date 2009-06-13
12 */
13
14#include "eglGraphicsBuffer.h"
16#include "config_egldisplay.h"
17#include "eglGraphicsPipe.h"
18
19#include "graphicsPipe.h"
20#include "pStatTimer.h"
21
22TypeHandle eglGraphicsBuffer::_type_handle;
23
24/**
25 *
26 */
27eglGraphicsBuffer::
28eglGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe,
29 const std::string &name,
30 const FrameBufferProperties &fb_prop,
31 const WindowProperties &win_prop,
32 int flags,
34 GraphicsOutput *host) :
35 GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
36{
37 eglGraphicsPipe *egl_pipe;
38 DCAST_INTO_V(egl_pipe, _pipe);
39 _pbuffer = EGL_NO_SURFACE;
40
41 // Since the pbuffer never gets flipped, we get screenshots from the same
42 // buffer we draw into.
43 _screenshot_buffer_type = _draw_buffer_type;
44}
45
46/**
47 *
48 */
49eglGraphicsBuffer::
50~eglGraphicsBuffer() {
51 nassertv(_pbuffer == EGL_NO_SURFACE);
52}
53
54/**
55 * This function will be called within the draw thread before beginning
56 * rendering for a given frame. It should do whatever setup is required, and
57 * return true if the frame should be rendered, or false if it should be
58 * skipped.
59 */
61begin_frame(FrameMode mode, Thread *current_thread) {
62 PStatTimer timer(_make_current_pcollector, current_thread);
63
64 begin_frame_spam(mode);
65 if (_gsg == nullptr) {
66 return false;
67 }
68
70 DCAST_INTO_R(eglgsg, _gsg, false);
71 if (!eglMakeCurrent(eglgsg->_egl_display, _pbuffer, _pbuffer, eglgsg->_context)) {
72 egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
73 << get_egl_error_string(eglGetError()) << "\n";
74 }
75
76 // Now that we have made the context current to a window, we can reset the
77 // GSG state if this is the first time it has been used. (We can't just
78 // call reset() when we construct the GSG, because reset() requires having a
79 // current context.)
80 eglgsg->reset_if_new();
81
82 if (mode == FM_render) {
83 CDLockedReader cdata(_cycler);
84 for (size_t i = 0; i != cdata->_textures.size(); ++i) {
85 const RenderTexture &rt = cdata->_textures[i];
86 RenderTextureMode rtm_mode = rt._rtm_mode;
87 if (rtm_mode == RTM_bind_or_copy) {
88 CDWriter cdataw(_cycler, cdata, false);
89 nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
90 cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
91 }
92 }
93 clear_cube_map_selection();
94 }
95
96 _gsg->set_current_properties(&get_fb_properties());
97 return _gsg->begin_frame(current_thread);
98}
99
100/**
101 * This function will be called within the draw thread after rendering is
102 * completed for a given frame. It should do whatever finalization is
103 * required.
104 */
106end_frame(FrameMode mode, Thread *current_thread) {
107 end_frame_spam(mode);
108 nassertv(_gsg != nullptr);
109
110 if (mode == FM_render) {
111 copy_to_textures();
112 }
113
114 _gsg->end_frame(current_thread);
115
116 if (mode == FM_render) {
117 trigger_flip();
118 clear_cube_map_selection();
119 }
120}
121
122/**
123 * Closes the buffer right now. Called from the window thread.
124 */
125void eglGraphicsBuffer::
126close_buffer() {
127 if (_gsg != nullptr) {
129 DCAST_INTO_V(eglgsg, _gsg);
130 if (!eglMakeCurrent(_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
131 egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
132 << get_egl_error_string(eglGetError()) << "\n";
133 }
134 _gsg.clear();
135
136 if (_pbuffer != EGL_NO_SURFACE) {
137 if (!eglDestroySurface(_egl_display, _pbuffer)) {
138 egldisplay_cat.error() << "Failed to destroy surface: "
139 << get_egl_error_string(eglGetError()) << "\n";
140 }
141 _pbuffer = EGL_NO_SURFACE;
142 }
143 }
144
145 _is_valid = false;
146}
147
148/**
149 * Opens the buffer right now. Called from the window thread. Returns true
150 * if the buffer is successfully opened, or false if there was a problem.
151 */
152bool eglGraphicsBuffer::
153open_buffer() {
154 eglGraphicsPipe *egl_pipe;
155 DCAST_INTO_R(egl_pipe, _pipe, false);
156
157 // GSG CreationInitialization
159 if (_gsg == 0) {
160 // There is no old gsg. Create a new one.
161 eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, nullptr);
162 eglgsg->choose_pixel_format(_fb_properties, egl_pipe, false, true, false);
163 _gsg = eglgsg;
164 } else {
165 // If the old gsg has the wrong pixel format, create a new one that shares
166 // with the old gsg.
167 DCAST_INTO_R(eglgsg, _gsg, false);
168 if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) {
169 eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg);
170 eglgsg->choose_pixel_format(_fb_properties, egl_pipe, false, true, false);
171 _gsg = eglgsg;
172 }
173 }
174
175 if (eglgsg->_fbconfig == nullptr) {
176 // If we didn't use an fbconfig to create the GSG, we can't create a
177 // PBuffer.
178 return false;
179 }
180
181 _egl_display = eglgsg->_egl_display;
182
183 int attrib_list[] = {
184 EGL_WIDTH, _size.get_x(),
185 EGL_HEIGHT, _size.get_y(),
186 EGL_NONE
187 };
188
189 _pbuffer = eglCreatePbufferSurface(eglgsg->_egl_display, eglgsg->_fbconfig, attrib_list);
190
191 if (_pbuffer == EGL_NO_SURFACE) {
192 egldisplay_cat.error()
193 << "Failed to create EGL pbuffer surface: "
194 << get_egl_error_string(eglGetError()) << "\n";
195 return false;
196 }
197
198 if (!eglMakeCurrent(eglgsg->_egl_display, _pbuffer, _pbuffer, eglgsg->_context)) {
199 egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
200 << get_egl_error_string(eglGetError()) << "\n";
201 }
202 eglgsg->reset_if_new();
203 if (!eglgsg->is_valid()) {
204 close_buffer();
205 return false;
206 }
208 (_fb_properties, eglgsg->get_gl_renderer())) {
209 close_buffer();
210 return false;
211 }
212 _fb_properties = eglgsg->get_fb_properties();
213
214 _is_valid = true;
215 return true;
216}
This template class calls PipelineCycler::read() in the constructor and PipelineCycler::release_read(...
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
bool verify_hardware_software(const FrameBufferProperties &props, const std::string &renderer) const
Validates that the properties represent the desired kind of renderer (hardware or software).
bool subsumes(const FrameBufferProperties &other) const
Returns true if this set of properties makes strictly greater or equal demands of the framebuffer tha...
An offscreen buffer for rendering into.
This class is the main interface to controlling the render process.
This is a base class for the various different classes that represent the result of a frame of render...
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
Encapsulates all the communication with a particular instance of a given rendering backend.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
A thread; that is, a lightweight process.
Definition: thread.h:46
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
A container for the various kinds of properties we might ask to have on a graphics window before we o...
virtual void end_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread after rendering is completed for a given frame.
virtual bool begin_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread before beginning rendering for a given frame.
This graphics pipe represents the interface for creating OpenGL ES graphics windows on an X-based (e....
A tiny specialization on GLESGraphicsStateGuardian to add some egl-specific information.
const FrameBufferProperties & get_fb_properties() const
Gets the FrameBufferProperties for all windows and buffers that use this GSG.
void choose_pixel_format(const FrameBufferProperties &properties, eglGraphicsPipe *egl_pipe, bool need_window, bool need_pbuffer, bool need_pixmap)
Selects a visual or fbconfig for all the windows and buffers that use this gsg.
const std::string get_egl_error_string(int error)
Returns the given EGL error as string.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.