41 PStatCollector GraphicsOutput::_make_current_pcollector(
"Draw:Make current");
42 PStatCollector GraphicsOutput::_copy_texture_pcollector(
"Draw:Copy texture");
47 CubeFaceDef(
const char *name,
const LPoint3 &look_at,
const LVector3 &up) :
48 _name(name), _look_at(look_at), _up(up) { }
55 static CubeFaceDef cube_faces[6] = {
56 CubeFaceDef(
"positive_x", LPoint3(1, 0, 0), LVector3(0, -1, 0)),
57 CubeFaceDef(
"negative_x", LPoint3(-1, 0, 0), LVector3(0, -1, 0)),
58 CubeFaceDef(
"positive_y", LPoint3(0, 1, 0), LVector3(0, 0, 1)),
59 CubeFaceDef(
"negative_y", LPoint3(0, -1, 0), LVector3(0, 0, -1)),
60 CubeFaceDef(
"positive_z", LPoint3(0, 0, 1), LVector3(0, -1, 0)),
61 CubeFaceDef(
"negative_z", LPoint3(0, 0, -1), LVector3(0, -1, 0))
76 bool default_stereo_flags) :
77 _lock(
"GraphicsOutput"),
78 _cull_window_pcollector(_cull_pcollector, name),
79 _draw_window_pcollector(_draw_pcollector, name),
80 _clear_window_pcollector(_draw_window_pcollector,
"Clear"),
83 #ifdef DO_MEMORY_USAGE
90 _fb_properties = fb_prop;
92 _creation_flags = flags;
94 _is_nonzero_size =
false;
97 _is_nonzero_size = (_size[0] > 0 && _size[1] > 0);
99 if (_creation_flags & GraphicsPipe::BF_size_track_host) {
101 _is_nonzero_size =
true;
106 _target_tex_page = -1;
107 _prev_page_dr =
nullptr;
110 _got_child_sort =
false;
111 _internal_sort_index = 0;
112 _inverted = window_inverted;
113 _swap_eyes = swap_eyes;
114 _red_blue_stereo =
false;
115 _left_eye_color_mask = 0x0f;
116 _right_eye_color_mask = 0x0f;
117 _side_by_side_stereo =
false;
118 _sbs_left_dimensions.set(0.0f, 1.0f, 0.0f, 1.0f);
119 _sbs_right_dimensions.set(0.0f, 1.0f, 0.0f, 1.0f);
120 _delete_flag =
false;
122 if (_fb_properties.is_single_buffered()) {
123 _draw_buffer_type = RenderBuffer::T_front;
125 _draw_buffer_type = RenderBuffer::T_back;
128 if (default_stereo_flags) {
131 _red_blue_stereo = red_blue_stereo && !fb_prop.is_stereo();
132 if (_red_blue_stereo) {
133 _left_eye_color_mask = parse_color_mask(red_blue_stereo_colors.
get_word(0));
134 _right_eye_color_mask = parse_color_mask(red_blue_stereo_colors.
get_word(1));
136 _side_by_side_stereo = side_by_side_stereo && !fb_prop.is_stereo();
137 if (_side_by_side_stereo) {
138 _sbs_left_dimensions.set(sbs_left_dimensions[0], sbs_left_dimensions[1],
139 sbs_left_dimensions[2], sbs_left_dimensions[3]);
140 _sbs_right_dimensions.set(sbs_right_dimensions[0], sbs_right_dimensions[1],
141 sbs_right_dimensions[2], sbs_right_dimensions[3]);
148 _overlay_display_region = make_mono_display_region(0.0f, 1.0f, 0.0f, 1.0f);
149 _overlay_display_region->set_active(
false);
150 _overlay_display_region->set_scissor_enabled(
false);
154 CDWriter cdata(_cycler,
true);
155 cdata->_active =
true;
159 set_clear_color_active(
true);
160 set_clear_depth_active(
true);
161 set_clear_stencil_active(
true);
162 set_clear_color(background_color.
get_value());
174 nassertv(_pipe ==
nullptr);
179 TotalDisplayRegions::iterator dri;
180 for (dri = _total_display_regions.begin();
181 dri != _total_display_regions.end();
183 (*dri)->_window =
nullptr;
186 _total_display_regions.clear();
187 _overlay_display_region =
nullptr;
197 cdata->_textures.clear();
198 ++(cdata->_textures_seq);
199 throw_event(
"render-texture-targets-changed");
238 RenderTexturePlane plane) {
240 if (mode == RTM_none) {
246 if (tex ==
nullptr) {
261 if (plane == RTP_COUNT) {
263 case Texture::F_depth_stencil:
264 plane = RTP_depth_stencil;
267 case Texture::F_depth_component:
268 case Texture::F_depth_component16:
269 case Texture::F_depth_component24:
270 case Texture::F_depth_component32:
283 if (plane == RTP_depth) {
287 }
else if (plane == RTP_depth_stencil) {
289 if (_fb_properties.get_float_depth()) {
296 }
else if (plane == RTP_color ||
297 plane == RTP_aux_rgba_0 ||
298 plane == RTP_aux_rgba_1 ||
299 plane == RTP_aux_rgba_2 ||
300 plane == RTP_aux_rgba_3) {
304 }
else if (plane == RTP_aux_hrgba_0 ||
305 plane == RTP_aux_hrgba_1 ||
306 plane == RTP_aux_hrgba_2 ||
307 plane == RTP_aux_hrgba_3) {
311 }
else if (plane == RTP_aux_float_0 ||
312 plane == RTP_aux_float_1 ||
313 plane == RTP_aux_float_2 ||
314 plane == RTP_aux_float_3) {
320 display_cat.error() <<
321 "add_render_texture: invalid bitplane specified.\n";
330 if (_fb_properties.is_stereo() && plane == RTP_color) {
339 if (mode == RTM_bind_or_copy) {
340 mode = RTM_copy_texture;
341 }
else if (mode == RTM_bind_layered) {
344 display_cat.error() <<
345 "add_render_texture: RTM_bind_layered was requested but "
346 "render-to-texture is not supported or has been disabled!\n";
350 if (mode == RTM_bind_layered && _gsg !=
nullptr && !_gsg->get_supports_geometry_shaders()) {
353 display_cat.warning() <<
354 "add_render_texture: RTM_bind_layered was requested but "
355 "geometry shaders are not supported!\n";
358 if (mode == RTM_bind_or_copy || mode == RTM_bind_layered) {
364 RenderTexture result;
365 result._texture = tex;
366 result._plane = plane;
367 result._rtm_mode = mode;
368 cdata->_textures.push_back(result);
369 ++(cdata->_textures_seq);
371 throw_event(
"render-texture-targets-changed");
383 display_cat.warning() <<
384 "Using deprecated setup_render_texture interface.\n";
388 }
else if (allow_bind) {
401 CDLockedReader cdata(_cycler);
402 if (cdata->_active != active) {
404 cdataw->_active = active;
417 CDLockedReader cdata(_cycler);
418 if (!cdata->_active) {
422 if (cdata->_one_shot_frame != -1) {
443 if (cdata->_active_display_regions_stale) {
446 return !cdataw->_active_display_regions.empty();
448 return !cdata->_active_display_regions.empty();
469 CDWriter cdata(_cycler,
true);
473 cdata->_one_shot_frame = -1;
483 CDReader cdata(_cycler);
500 if (_inverted != inverted) {
501 _inverted = inverted;
506 TotalDisplayRegions::iterator dri;
507 for (dri = _total_display_regions.begin();
508 dri != _total_display_regions.end();
529 LVecBase4 left, right;
530 left.set(sbs_left_dimensions[0], sbs_left_dimensions[1],
531 sbs_left_dimensions[2], sbs_left_dimensions[3]);
532 right.set(sbs_right_dimensions[0], sbs_right_dimensions[1],
533 sbs_right_dimensions[2], sbs_right_dimensions[3]);
550 const LVecBase4 &sbs_left_dimensions,
551 const LVecBase4 &sbs_right_dimensions) {
552 _side_by_side_stereo = side_by_side_stereo;
553 if (_side_by_side_stereo) {
554 _sbs_left_dimensions = sbs_left_dimensions;
555 _sbs_right_dimensions = sbs_right_dimensions;
557 _sbs_left_dimensions.set(0.0f, 1.0f, 0.0f, 1.0f);
558 _sbs_right_dimensions.set(0.0f, 1.0f, 0.0f, 1.0f);
571 for (
int i = 0; i < (int)_hold_textures.size(); i++) {
572 if (_hold_textures[i].is_valid_pointer()) {
587 if (_gsg !=
nullptr &&
588 _gsg->get_engine() !=
nullptr) {
589 _gsg->get_engine()->set_window_sort(
this, sort);
605 if (
is_stereo() && default_stereo_camera) {
624 if (_side_by_side_stereo) {
644 if (_side_by_side_stereo) {
647 PN_stdfloat left_l = _sbs_left_dimensions[0];
648 PN_stdfloat left_b = _sbs_left_dimensions[2];
649 PN_stdfloat left_w = _sbs_left_dimensions[1] - _sbs_left_dimensions[0];
650 PN_stdfloat left_h = _sbs_left_dimensions[3] - _sbs_left_dimensions[2];
651 LVecBase4 left_dimensions(dimensions[0] * left_w + left_l,
652 dimensions[1] * left_w + left_l,
653 dimensions[2] * left_h + left_b,
654 dimensions[3] * left_h + left_b);
657 PN_stdfloat right_l = _sbs_right_dimensions[0];
658 PN_stdfloat right_b = _sbs_right_dimensions[2];
659 PN_stdfloat right_w = _sbs_right_dimensions[1] - _sbs_right_dimensions[0];
660 PN_stdfloat right_h = _sbs_right_dimensions[3] - _sbs_right_dimensions[2];
661 LVecBase4 right_dimensions(dimensions[0] * right_w + right_l,
662 dimensions[1] * right_w + right_l,
663 dimensions[2] * right_h + right_b,
664 dimensions[3] * right_h + right_b);
683 right->set_clear_depth_active(
true);
686 right->set_clear_stencil_active(
true);
707 nassertr(display_region != _overlay_display_region,
false);
711 DCAST_INTO_R(sdr, display_region,
false);
716 return do_remove_display_region(display_region);
727 TotalDisplayRegions::iterator dri;
728 for (dri = _total_display_regions.begin();
729 dri != _total_display_regions.end();
732 if (display_region != _overlay_display_region) {
735 display_region->_window =
nullptr;
738 _total_display_regions.clear();
739 _total_display_regions.push_back(_overlay_display_region);
741 OPEN_ITERATE_ALL_STAGES(_cycler) {
743 cdata->_active_display_regions_stale =
true;
745 CLOSE_ITERATE_ALL_STAGES(_cycler);
763 nassertv(display_region->
get_window() ==
this);
764 _overlay_display_region = display_region;
774 return _total_display_regions.size();
784 get_display_region(
int n)
const {
785 determine_display_regions();
789 if (n >= 0 && n < (
int)_total_display_regions.size()) {
790 result = _total_display_regions[n];
803 get_num_active_display_regions()
const {
804 determine_display_regions();
805 CDReader cdata(_cycler);
806 return cdata->_active_display_regions.size();
816 get_active_display_region(
int n)
const {
817 determine_display_regions();
819 CDReader cdata(_cycler);
820 if (n >= 0 && n < (
int)cdata->_active_display_regions.size()) {
821 return cdata->_active_display_regions[n];
851 make_texture_buffer(
const string &name,
int x_size,
int y_size,
855 props.set_rgb_color(1);
857 props.set_alpha_bits(1);
858 props.set_depth_bits(1);
860 if (fbp ==
nullptr) {
864 int flags = GraphicsPipe::BF_refuse_window;
865 if (textures_power_2 != ATS_none) {
866 flags |= GraphicsPipe::BF_size_power_2;
868 if (tex !=
nullptr &&
870 flags |= GraphicsPipe::BF_size_square;
879 if (buffer !=
nullptr) {
880 if (buffer->
get_gsg() ==
nullptr ||
881 buffer->
get_gsg()->get_prepared_objects() !=
get_gsg()->get_prepared_objects()) {
920 display_cat.warning()
921 <<
"Cannot make dynamic cube map; GSG does not support cube maps.\n";
924 if (max_dimension > 0) {
925 size = std::min(max_dimension, size);
942 buffer = make_texture_buffer(name, size, size, tex, to_ram, fbp);
952 for (
int i = 0; i < 6; i++) {
954 camera->set_lens(lens);
955 camera->set_camera_mask(camera_mask);
957 camera_np.
look_at(cube_faces[i]._look_at, cube_faces[i]._up);
983 if (_texture_card ==
nullptr) {
986 strip->set_shade_model(Geom::SM_uniform);
987 strip->add_next_vertices(4);
988 strip->close_primitive();
990 geom->add_primitive(strip);
991 _texture_card =
new GeomNode(
"texture card");
992 _texture_card->add_geom(geom);
996 path.
node()->add_child(_texture_card);
1002 RenderTextures::const_iterator ri;
1003 for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
1004 Texture *texture = (*ri)._texture;
1005 if ((texture->
get_format() != Texture::F_depth_stencil)) {
1093 <<
"Resetting " << get_type() <<
"\n";
1115 _is_nonzero_size = (x > 0 && y > 0);
1120 TotalDisplayRegions::iterator dri;
1121 for (dri = _total_display_regions.begin();
1122 dri != _total_display_regions.end();
1124 (*dri)->compute_pixels_all_stages(fb_x_size, fb_y_size);
1127 if (_texture_card !=
nullptr && _texture_card->get_num_geoms() > 0) {
1128 _texture_card->modify_geom(0)->set_vertex_data(create_texture_card_vdata(x, y));
1142 if (display_cat.is_spam()) {
1144 <<
"clear(): " << get_type() <<
" "
1145 <<
get_name() <<
" " << (
void *)
this <<
"\n";
1148 nassertv(_gsg !=
nullptr);
1151 _gsg->prepare_display_region(&dr_reader);
1185 if (new_target_tex_page != -1 && new_target_tex_page != _target_tex_page) {
1187 if (new_target_tex_page == -1) {
1188 new_target_tex_page = 0;
1190 int old_target_tex_page = _target_tex_page;
1192 _target_tex_page = new_target_tex_page;
1193 _prev_page_dr = new_dr->get_object();
1196 RenderTextures::const_iterator ri;
1197 for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
1198 RenderTextureMode rtm_mode = (*ri)._rtm_mode;
1199 RenderTexturePlane plane = (*ri)._plane;
1200 Texture *texture = (*ri)._texture;
1201 if (rtm_mode != RTM_none) {
1202 if (rtm_mode == RTM_bind_or_copy || rtm_mode == RTM_bind_layered) {
1208 }
else if (old_target_tex_page != -1) {
1212 nassertv(old_page_dr !=
nullptr);
1213 if (display_cat.is_debug()) {
1215 <<
"Copying texture for " <<
get_name() <<
" at scene change.\n";
1217 <<
"target_tex_page = " << old_target_tex_page <<
"\n";
1222 if (plane == RTP_color && _fb_properties.is_stereo()) {
1224 RenderBuffer left(_gsg, buffer._buffer_type & ~RenderBuffer::T_right);
1225 RenderBuffer right(_gsg, buffer._buffer_type & ~RenderBuffer::T_left);
1227 if (rtm_mode == RTM_copy_ram) {
1228 _gsg->framebuffer_copy_to_ram(texture, 0, old_target_tex_page,
1230 _gsg->framebuffer_copy_to_ram(texture, 1, old_target_tex_page,
1231 old_page_dr, right);
1233 _gsg->framebuffer_copy_to_texture(texture, 0, old_target_tex_page,
1235 _gsg->framebuffer_copy_to_texture(texture, 1, old_target_tex_page,
1236 old_page_dr, right);
1239 if (rtm_mode == RTM_copy_ram) {
1240 _gsg->framebuffer_copy_to_ram(texture, 0, old_target_tex_page,
1241 old_page_dr, buffer);
1243 _gsg->framebuffer_copy_to_texture(texture, 0, old_target_tex_page,
1244 old_page_dr, buffer);
1300 _flip_ready =
false;
1316 void GraphicsOutput::
1317 pixel_factor_changed() {
1327 void GraphicsOutput::
1328 prepare_for_deletion() {
1329 CDWriter cdata(_cycler,
true);
1330 cdata->_active =
false;
1334 RenderTextures::iterator ri;
1335 for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
1336 if ((*ri)._rtm_mode == RTM_bind_or_copy || (*ri)._rtm_mode == RTM_bind_layered) {
1337 _hold_textures.push_back((*ri)._texture);
1340 cdata->_textures.clear();
1342 _delete_flag =
true;
1356 void GraphicsOutput::
1357 promote_to_copy_texture() {
1358 CDLockedReader cdata(_cycler);
1359 RenderTextures::const_iterator ri;
1361 bool any_bind =
false;
1362 for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
1363 if ((*ri)._rtm_mode == RTM_bind_or_copy) {
1370 RenderTextures::iterator ri;
1371 for (ri = cdataw->_textures.begin(); ri != cdataw->_textures.end(); ++ri) {
1372 if ((*ri)._rtm_mode == RTM_bind_or_copy) {
1373 (*ri)._rtm_mode = RTM_copy_texture;
1386 bool GraphicsOutput::
1387 copy_to_textures() {
1390 CDReader cdata(_cycler);
1391 RenderTextures::const_iterator ri;
1392 for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
1393 RenderTextureMode rtm_mode = (*ri)._rtm_mode;
1394 if ((rtm_mode == RTM_none) || (rtm_mode == RTM_bind_or_copy)) {
1398 Texture *texture = (*ri)._texture;
1401 if ((rtm_mode == RTM_copy_texture)||
1402 (rtm_mode == RTM_copy_ram)||
1403 ((rtm_mode == RTM_triggered_copy_texture)&&(_trigger_copy))||
1404 ((rtm_mode == RTM_triggered_copy_ram)&&(_trigger_copy))) {
1405 if (display_cat.is_debug()) {
1407 <<
"Copying texture for " <<
get_name() <<
" at frame end.\n";
1409 <<
"target_tex_page = " << _target_tex_page <<
"\n";
1411 RenderTexturePlane plane = (*ri)._plane;
1413 if (plane == RTP_color) {
1418 bool copied =
false;
1420 if (_prev_page_dr !=
nullptr) {
1424 if (plane == RTP_color && _fb_properties.is_stereo()) {
1426 RenderBuffer left(_gsg, buffer._buffer_type & ~RenderBuffer::T_right);
1427 RenderBuffer right(_gsg, buffer._buffer_type & ~RenderBuffer::T_left);
1429 if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
1430 copied = _gsg->framebuffer_copy_to_ram(texture, 0, _target_tex_page,
1432 copied = _gsg->framebuffer_copy_to_ram(texture, 1, _target_tex_page,
1433 dr, right) && copied;
1435 copied = _gsg->framebuffer_copy_to_texture(texture, 0, _target_tex_page,
1437 copied = _gsg->framebuffer_copy_to_texture(texture, 1, _target_tex_page,
1438 dr, right) && copied;
1441 if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
1442 copied = _gsg->framebuffer_copy_to_ram(texture, 0, _target_tex_page,
1445 copied = _gsg->framebuffer_copy_to_texture(texture, 0, _target_tex_page,
1454 if (_trigger_copy !=
nullptr) {
1455 _trigger_copy->set_result(
nullptr);
1456 _trigger_copy =
nullptr;
1466 create_texture_card_vdata(
int x,
int y) {
1467 PN_stdfloat xhi = 1.0;
1468 PN_stdfloat yhi = 1.0;
1473 xhi = (x * 1.0f) / xru;
1474 yhi = (y * 1.0f) / yru;
1480 (
"card", format, Geom::UH_static);
1486 vertex.
add_data3(LVertex::rfu(-1.0f, 0.0f, 1.0f));
1487 vertex.
add_data3(LVertex::rfu(-1.0f, 0.0f, -1.0f));
1488 vertex.
add_data3(LVertex::rfu( 1.0f, 0.0f, 1.0f));
1489 vertex.
add_data3(LVertex::rfu( 1.0f, 0.0f, -1.0f));
1511 CDWriter cdata(_cycler,
true);
1512 cdata->_active_display_regions_stale =
true;
1514 _total_display_regions.push_back(display_region);
1516 return display_region;
1523 bool GraphicsOutput::
1525 nassertr(display_region != _overlay_display_region,
false);
1528 TotalDisplayRegions::iterator dri =
1529 find(_total_display_regions.begin(), _total_display_regions.end(), drp);
1530 if (dri != _total_display_regions.end()) {
1533 display_region->_window =
nullptr;
1534 _total_display_regions.erase(dri);
1536 OPEN_ITERATE_ALL_STAGES(_cycler) {
1537 CDStageWriter cdata(_cycler, pipeline_stage);
1538 cdata->_active_display_regions_stale =
true;
1540 CLOSE_ITERATE_ALL_STAGES(_cycler);
1550 void GraphicsOutput::
1551 do_determine_display_regions(GraphicsOutput::CData *cdata) {
1552 cdata->_active_display_regions_stale =
false;
1554 cdata->_active_display_regions.clear();
1555 cdata->_active_display_regions.reserve(_total_display_regions.size());
1558 TotalDisplayRegions::const_iterator dri;
1559 for (dri = _total_display_regions.begin();
1560 dri != _total_display_regions.end();
1564 cdata->_active_display_regions.push_back(display_region);
1565 display_region->set_active_index(index);
1568 display_region->set_active_index(-1);
1572 std::stable_sort(cdata->_active_display_regions.begin(),
1573 cdata->_active_display_regions.end(),
1583 unsigned int GraphicsOutput::
1584 parse_color_mask(
const string &word) {
1585 unsigned int result = 0;
1586 vector_string components;
1589 vector_string::const_iterator ci;
1590 for (ci = components.begin(); ci != components.end(); ++ci) {
1592 if (w ==
"red" || w ==
"r") {
1595 }
else if (w ==
"green" || w ==
"g") {
1598 }
else if (w ==
"blue" || w ==
"b") {
1601 }
else if (w ==
"yellow" || w ==
"y") {
1604 }
else if (w ==
"magenta" || w ==
"m") {
1607 }
else if (w ==
"cyan" || w ==
"c") {
1610 }
else if (w ==
"alpha" || w ==
"a") {
1613 }
else if (w ==
"off") {
1616 display_cat.warning()
1617 <<
"Invalid color in red-blue-stereo-colors: " << (*ci) <<
"\n";
1627 GraphicsOutput::CData::
1633 _one_shot_frame = -1;
1634 _active_display_regions_stale =
false;
1640 GraphicsOutput::CData::
1641 CData(
const GraphicsOutput::CData ©) :
1642 _textures(copy._textures),
1643 _active(copy._active),
1644 _one_shot_frame(copy._one_shot_frame),
1645 _active_display_regions(copy._active_display_regions),
1646 _active_display_regions_stale(copy._active_display_regions_stale)
1655 return new CData(*
this);
1662 operator << (std::ostream &out, GraphicsOutput::FrameMode fm) {
1664 case GraphicsOutput::FM_render:
1665 return out <<
"render";
1666 case GraphicsOutput::FM_parasite:
1667 return out <<
"parasite";
1668 case GraphicsOutput::FM_refresh:
1669 return out <<
"refresh";
1672 return out <<
"(**invalid GraphicsOutput::FrameMode(" << (int)fm <<
")**)";