Panda3D
Loading...
Searching...
No Matches
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 // EGL pbuffers only have a back buffer (see 2.2.2 in spec), and it is never
42 // flipped (eglSwapBuffers is a no-op).
43 _draw_buffer_type = RenderBuffer::T_back;
44 _screenshot_buffer_type = RenderBuffer::T_back;
45}
46
47/**
48 *
49 */
50eglGraphicsBuffer::
51~eglGraphicsBuffer() {
52 nassertv(_pbuffer == EGL_NO_SURFACE);
53}
54
55/**
56 * This function will be called within the draw thread before beginning
57 * rendering for a given frame. It should do whatever setup is required, and
58 * return true if the frame should be rendered, or false if it should be
59 * skipped.
60 */
62begin_frame(FrameMode mode, Thread *current_thread) {
63 PStatTimer timer(_make_current_pcollector, current_thread);
64
65 begin_frame_spam(mode);
66 if (_gsg == nullptr) {
67 return false;
68 }
69
71 DCAST_INTO_R(eglgsg, _gsg, false);
72 if (!eglMakeCurrent(eglgsg->_egl_display, _pbuffer, _pbuffer, eglgsg->_context)) {
73 egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
74 << get_egl_error_string(eglGetError()) << "\n";
75 }
76
77 // Now that we have made the context current to a window, we can reset the
78 // GSG state if this is the first time it has been used. (We can't just
79 // call reset() when we construct the GSG, because reset() requires having a
80 // current context.)
81 eglgsg->reset_if_new();
82
83 if (mode == FM_render) {
84 CDLockedReader cdata(_cycler);
85 for (size_t i = 0; i != cdata->_textures.size(); ++i) {
86 const RenderTexture &rt = cdata->_textures[i];
87 RenderTextureMode rtm_mode = rt._rtm_mode;
88 if (rtm_mode == RTM_bind_or_copy) {
89 CDWriter cdataw(_cycler, cdata, false);
90 nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
91 cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
92 }
93 }
94 clear_cube_map_selection();
95 }
96
97 _gsg->set_current_properties(&get_fb_properties());
98 return _gsg->begin_frame(current_thread);
99}
100
101/**
102 * This function will be called within the draw thread after rendering is
103 * completed for a given frame. It should do whatever finalization is
104 * required.
105 */
107end_frame(FrameMode mode, Thread *current_thread) {
108 end_frame_spam(mode);
109 nassertv(_gsg != nullptr);
110
111 if (mode == FM_render) {
112 copy_to_textures();
113 }
114
115 _gsg->end_frame(current_thread);
116
117 if (mode == FM_render) {
118 trigger_flip();
119 clear_cube_map_selection();
120 }
121}
122
123/**
124 *
125 */
127set_size(int x, int y) {
128 nassertv_always(_gsg != nullptr);
129
130 if (_size.get_x() != x || _size.get_y() != y) {
131 eglDestroySurface(_egl_display, _pbuffer);
132
133 int attrib_list[] = {
134 EGL_WIDTH, x,
135 EGL_HEIGHT, y,
136 EGL_NONE
137 };
138
140 DCAST_INTO_V(eglgsg, _gsg);
141 _pbuffer = eglCreatePbufferSurface(eglgsg->_egl_display, eglgsg->_fbconfig, attrib_list);
142 }
143
145}
146
147/**
148 * Closes the buffer right now. Called from the window thread.
149 */
150void eglGraphicsBuffer::
151close_buffer() {
152 if (_gsg != nullptr) {
154 DCAST_INTO_V(eglgsg, _gsg);
155 if (!eglMakeCurrent(_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
156 egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
157 << get_egl_error_string(eglGetError()) << "\n";
158 }
159 _gsg.clear();
160
161 if (_pbuffer != EGL_NO_SURFACE) {
162 if (!eglDestroySurface(_egl_display, _pbuffer)) {
163 egldisplay_cat.error() << "Failed to destroy surface: "
164 << get_egl_error_string(eglGetError()) << "\n";
165 }
166 _pbuffer = EGL_NO_SURFACE;
167 }
168 }
169
170 _is_valid = false;
171}
172
173/**
174 * Opens the buffer right now. Called from the window thread. Returns true
175 * if the buffer is successfully opened, or false if there was a problem.
176 */
177bool eglGraphicsBuffer::
178open_buffer() {
179 eglGraphicsPipe *egl_pipe;
180 DCAST_INTO_R(egl_pipe, _pipe, false);
181
182 // GSG CreationInitialization
184 if (_gsg == 0) {
185 // There is no old gsg. Create a new one.
186 eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, nullptr);
187 eglgsg->choose_pixel_format(_fb_properties, egl_pipe, false, true, false);
188 _gsg = eglgsg;
189 } else {
190 // If the old gsg has the wrong pixel format, create a new one that shares
191 // with the old gsg.
192 DCAST_INTO_R(eglgsg, _gsg, false);
193 if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) {
194 eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg);
195 eglgsg->choose_pixel_format(_fb_properties, egl_pipe, false, true, false);
196 _gsg = eglgsg;
197 }
198 }
199
200 if (eglgsg->_fbconfig == nullptr) {
201 // If we didn't use an fbconfig to create the GSG, we can't create a
202 // PBuffer.
203 return false;
204 }
205
206 _egl_display = eglgsg->_egl_display;
207
208 int attrib_list[] = {
209 EGL_WIDTH, _size.get_x(),
210 EGL_HEIGHT, _size.get_y(),
211 EGL_NONE
212 };
213
214 _pbuffer = eglCreatePbufferSurface(eglgsg->_egl_display, eglgsg->_fbconfig, attrib_list);
215
216 if (_pbuffer == EGL_NO_SURFACE) {
217 egldisplay_cat.error()
218 << "Failed to create EGL pbuffer surface: "
219 << get_egl_error_string(eglGetError()) << "\n";
220 return false;
221 }
222
223 if (!eglMakeCurrent(eglgsg->_egl_display, _pbuffer, _pbuffer, eglgsg->_context)) {
224 egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
225 << get_egl_error_string(eglGetError()) << "\n";
226 }
227 eglgsg->reset_if_new();
228 if (!eglgsg->is_valid()) {
229 close_buffer();
230 return false;
231 }
233 (_fb_properties, eglgsg->get_gl_renderer())) {
234 close_buffer();
235 return false;
236 }
237 _fb_properties = eglgsg->get_fb_properties();
238
239 _is_valid = true;
240 return true;
241}
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.
void set_size_and_recalc(int x, int y)
Changes the x_size and y_size, then recalculates structures that depend on size.
An object to create GraphicsOutputs that share a particular 3-D API.
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 set_size(int x, int y)
This is called by the GraphicsEngine to request that the buffer resize itself.
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.