|
@@ -1,5 +1,4 @@
|
|
|
#include "osg_helper.h"
|
|
#include "osg_helper.h"
|
|
|
-#include "third_party/scope_guard.hpp"
|
|
|
|
|
|
|
|
|
|
#include <glad/gl.h>
|
|
#include <glad/gl.h>
|
|
|
|
|
|
|
@@ -37,6 +36,7 @@ ogl_buffer_proxy::~ogl_buffer_proxy() {
|
|
|
|
|
|
|
|
void ogl_buffer_proxy::upload(const sp_image &img) {
|
|
void ogl_buffer_proxy::upload(const sp_image &img) {
|
|
|
create(img.byte_size());
|
|
create(img.byte_size());
|
|
|
|
|
+ modify_ts = current_timestamp();
|
|
|
auto status = img.mem->status();
|
|
auto status = img.mem->status();
|
|
|
if (status.cuda_available
|
|
if (status.cuda_available
|
|
|
|| (status.host_available && !img.is_dense())) {
|
|
|| (status.host_available && !img.is_dense())) {
|
|
@@ -62,6 +62,21 @@ void ogl_buffer_proxy::upload(const sp_image &img) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+void ogl_buffer_proxy::download(sp_image &img) {
|
|
|
|
|
+ assert(used_size == img.byte_size());
|
|
|
|
|
+ if (!down_res) [[unlikely]] {
|
|
|
|
|
+ down_res.emplace(id, cudaGraphicsMapFlagsReadOnly);
|
|
|
|
|
+ }
|
|
|
|
|
+ const auto read_helper = write_access_helper(img.cuda());
|
|
|
|
|
+ const auto img_ptr = img.start_ptr(read_helper.ptr());
|
|
|
|
|
+ size_t res_size = 0;
|
|
|
|
|
+ const auto res_ptr = up_res->mapped_ptr(&res_size);
|
|
|
|
|
+ assert(res_size >= img.byte_size());
|
|
|
|
|
+ CUDA_API_CHECK(cudaMemcpy2DAsync(img_ptr, img.pitch(), res_ptr, img.byte_width(),
|
|
|
|
|
+ img.byte_width(), img.height(), cudaMemcpyDeviceToDevice, current_cuda_stream()));
|
|
|
|
|
+ down_res->unmap();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
void Texture2DSP::setImageSP(const sp_image &img) {
|
|
void Texture2DSP::setImageSP(const sp_image &img) {
|
|
|
assert(getTextureWidth() == img.width());
|
|
assert(getTextureWidth() == img.width());
|
|
|
assert(getTextureHeight() == img.height());
|
|
assert(getTextureHeight() == img.height());
|
|
@@ -71,45 +86,186 @@ void Texture2DSP::setImageSP(const sp_image &img) {
|
|
|
setSourceType(get_tex_type(img.cv_type()));
|
|
setSourceType(get_tex_type(img.cv_type()));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+namespace {
|
|
|
|
|
+ auto get_tex_format_channels(const GLenum format) {
|
|
|
|
|
+ switch (format) {
|
|
|
|
|
+ // @formatter:off
|
|
|
|
|
+ case GL_DEPTH_COMPONENT:
|
|
|
|
|
+ case GL_RED:
|
|
|
|
|
+ case GL_GREEN:
|
|
|
|
|
+ case GL_BLUE: { return 1; }
|
|
|
|
|
+ case GL_RGB:
|
|
|
|
|
+ case GL_BGR: { return 3; }
|
|
|
|
|
+ case GL_RGBA:
|
|
|
|
|
+ case GL_BGRA: { return 4; }
|
|
|
|
|
+ default: { assert(false); return 0; };
|
|
|
|
|
+ // @formatter:on
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ auto get_date_type_cv_depth(const GLenum type) {
|
|
|
|
|
+ switch (type) {
|
|
|
|
|
+ // @formatter:off
|
|
|
|
|
+ case GL_UNSIGNED_BYTE:
|
|
|
|
|
+ case GL_UNSIGNED_INT_8_8_8_8_REV: { return CV_8U; }
|
|
|
|
|
+ case GL_FLOAT: { return CV_32F; }
|
|
|
|
|
+ default: { assert(false); return 0; };
|
|
|
|
|
+ // @formatter:on
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+sp_image Texture2DSP::asImageSP(GLenum format, GLenum type) {
|
|
|
|
|
+ const auto channels = get_tex_format_channels(format);
|
|
|
|
|
+ const auto cv_depth = get_date_type_cv_depth(type);
|
|
|
|
|
+ const auto cv_type = CV_MAKE_TYPE(cv_depth, channels);
|
|
|
|
|
+ const auto img_size = cv::Size(getTextureWidth(), getTextureHeight());
|
|
|
|
|
+ auto img = sp_image::create(cv_type, img_size);
|
|
|
|
|
+
|
|
|
|
|
+ if (!pbo) [[unlikely]] { pbo.emplace(); }
|
|
|
|
|
+ if (pbo->modify_ts < draw_ts) {
|
|
|
|
|
+ pbo->create(img.byte_size());
|
|
|
|
|
+ glBindTexture(getTextureTarget(), getTextureObject(0)->id());
|
|
|
|
|
+ glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo->id);
|
|
|
|
|
+ glReadPixels(0, 0, img.width(), img.height(), format, type, (void *) 0);
|
|
|
|
|
+ glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
|
|
|
|
+ glBindTexture(getTextureTarget(), 0);
|
|
|
|
|
+ pbo->modify_ts = current_timestamp();
|
|
|
|
|
+ }
|
|
|
|
|
+ pbo->download(img);
|
|
|
|
|
+ return img;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
void Texture2DSP::apply(osg::State &state) const {
|
|
void Texture2DSP::apply(osg::State &state) const {
|
|
|
setNumMipmapLevels(1);
|
|
setNumMipmapLevels(1);
|
|
|
Texture2D::apply(state);
|
|
Texture2D::apply(state);
|
|
|
// texture has already been bind
|
|
// texture has already been bind
|
|
|
|
|
|
|
|
if (!pbo) return;
|
|
if (!pbo) return;
|
|
|
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo->id);
|
|
|
|
|
- glTexSubImage2D(getTextureTarget(), 0, 0, 0,
|
|
|
|
|
- getTextureWidth(), getTextureHeight(),
|
|
|
|
|
- getSourceFormat(), getSourceType(), nullptr);
|
|
|
|
|
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
|
|
|
|
|
|
+ if (download_ts < pbo->modify_ts) {
|
|
|
|
|
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo->id);
|
|
|
|
|
+ glTexSubImage2D(getTextureTarget(), 0, 0, 0,
|
|
|
|
|
+ getTextureWidth(), getTextureHeight(),
|
|
|
|
|
+ getSourceFormat(), getSourceType(), nullptr);
|
|
|
|
|
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
|
|
|
|
+ download_ts = current_timestamp();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-constexpr auto image_vertex_num = 4;
|
|
|
|
|
|
|
+#include "render_osg/osg_utility.h"
|
|
|
|
|
+
|
|
|
|
|
+#include <osg/Program>
|
|
|
|
|
+
|
|
|
|
|
+using namespace osg;
|
|
|
|
|
+
|
|
|
|
|
+namespace {
|
|
|
|
|
+ constexpr auto image_vertex_num = 4;
|
|
|
|
|
+
|
|
|
|
|
+ struct prog_image_default_type {
|
|
|
|
|
+ ref_ptr<Program> prog;
|
|
|
|
|
+ ref_ptr<Uniform> image_tex;
|
|
|
|
|
+
|
|
|
|
|
+ prog_image_default_type() {
|
|
|
|
|
+ prog = new Program();
|
|
|
|
|
+ prog->addShader(new Shader(
|
|
|
|
|
+ Shader::VERTEX, load_shader("image_2d.vert")));
|
|
|
|
|
+ prog->addShader(new Shader(
|
|
|
|
|
+ Shader::FRAGMENT, load_shader("image_default.frag")));
|
|
|
|
|
+ image_tex = new Uniform(Uniform::INT, "image_tex");
|
|
|
|
|
+ image_tex->set(0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void apply(StateSet *state) const {
|
|
|
|
|
+ state->setAttributeAndModes(prog);
|
|
|
|
|
+ state->addUniform(image_tex);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ struct prog_image_remap_type {
|
|
|
|
|
+ ref_ptr<Program> prog;
|
|
|
|
|
+ ref_ptr<Uniform> image_tex;
|
|
|
|
|
+ ref_ptr<Uniform> remap_tex;
|
|
|
|
|
+
|
|
|
|
|
+ prog_image_remap_type() {
|
|
|
|
|
+ prog = new Program();
|
|
|
|
|
+ prog->addShader(new Shader(
|
|
|
|
|
+ Shader::VERTEX, load_shader("image_2d.vert")));
|
|
|
|
|
+ prog->addShader(new Shader(
|
|
|
|
|
+ Shader::FRAGMENT, load_shader("image_remap.frag")));
|
|
|
|
|
+ image_tex = new Uniform("image_tex", 0);
|
|
|
|
|
+ remap_tex = new Uniform("remap_tex", 1);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void apply(StateSet *state) const {
|
|
|
|
|
+ state->setAttributeAndModes(prog);
|
|
|
|
|
+ state->addUniform(image_tex);
|
|
|
|
|
+ state->addUniform(remap_tex);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ std::optional<prog_image_default_type> prog_image_default;
|
|
|
|
|
+ std::optional<prog_image_remap_type> prog_image_remap;
|
|
|
|
|
+
|
|
|
|
|
+ void setup_program(ImageGeomSP *img) {
|
|
|
|
|
+ assert(img != nullptr);
|
|
|
|
|
+ if (img->remap_tex) {
|
|
|
|
|
+ if (!prog_image_remap) [[unlikely]] {
|
|
|
|
|
+ prog_image_remap.emplace();
|
|
|
|
|
+ }
|
|
|
|
|
+ prog_image_remap->apply(img->getOrCreateStateSet());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (!prog_image_default) [[unlikely]] {
|
|
|
|
|
+ prog_image_default.emplace();
|
|
|
|
|
+ }
|
|
|
|
|
+ prog_image_default->apply(img->getOrCreateStateSet());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void upload_image_to_texture(const sp_image &img, ref_ptr<Texture2DSP> &tex) {
|
|
|
|
|
+ if (tex == nullptr
|
|
|
|
|
+ || tex->getTextureWidth() != img.width()
|
|
|
|
|
+ || tex->getTextureHeight() != img.height()) {
|
|
|
|
|
+ const auto next_tex = new Texture2DSP();
|
|
|
|
|
+ next_tex->setTextureSize(img.width(), img.height());
|
|
|
|
|
+ next_tex->setInternalFormat(GL_RGBA);
|
|
|
|
|
+ tex = next_tex;
|
|
|
|
|
+ }
|
|
|
|
|
+ tex->setImageSP(img);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
ImageGeomSP::ImageGeomSP() {
|
|
ImageGeomSP::ImageGeomSP() {
|
|
|
- const osg::ref_ptr tex_uv = new osg::Vec2Array();
|
|
|
|
|
|
|
+ const ref_ptr vertex = new Vec3Array(image_vertex_num);
|
|
|
|
|
+ vertex->setName("vertex");
|
|
|
|
|
+ setVertexArray(vertex);
|
|
|
|
|
+ setViewportRange({-1, -1, 2, 2});
|
|
|
|
|
+
|
|
|
|
|
+ const ref_ptr tex_uv = new Vec2Array();
|
|
|
|
|
+ tex_uv->setName("vertex_uv");
|
|
|
tex_uv->push_back({0, 0});
|
|
tex_uv->push_back({0, 0});
|
|
|
tex_uv->push_back({1, 0});
|
|
tex_uv->push_back({1, 0});
|
|
|
tex_uv->push_back({1, 1});
|
|
tex_uv->push_back({1, 1});
|
|
|
tex_uv->push_back({0, 1});
|
|
tex_uv->push_back({0, 1});
|
|
|
- setTexCoordArray(0, tex_uv);
|
|
|
|
|
|
|
+ setVertexAttribArray(1, tex_uv, Array::BIND_PER_VERTEX);
|
|
|
|
|
|
|
|
- const osg::ref_ptr colors = new osg::Vec4Array();
|
|
|
|
|
|
|
+ const ref_ptr colors = new Vec4Array();
|
|
|
|
|
+ colors->setName("color");
|
|
|
colors->push_back({1, 1, 1, 1});
|
|
colors->push_back({1, 1, 1, 1});
|
|
|
- setColorArray(colors, osg::Array::BIND_OVERALL);
|
|
|
|
|
|
|
+ setColorArray(colors, Array::BIND_OVERALL);
|
|
|
|
|
|
|
|
- const osg::ref_ptr vertex = new osg::Vec3Array(image_vertex_num);
|
|
|
|
|
- setVertexArray(vertex);
|
|
|
|
|
- setViewportRange({-1, -1, 2, 2});
|
|
|
|
|
|
|
+ addPrimitiveSet(new DrawArrays(
|
|
|
|
|
+ PrimitiveSet::QUADS, 0, 4));
|
|
|
|
|
+ setup_program(this);
|
|
|
|
|
|
|
|
- addPrimitiveSet(new osg::DrawArrays(
|
|
|
|
|
- osg::PrimitiveSet::QUADS, 0, 4));
|
|
|
|
|
|
|
+ ArrayList array_list;
|
|
|
|
|
+ getArrayList(array_list);
|
|
|
|
|
+ array_list.clear();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ImageGeomSP::setViewportRange(simple_rect rect) {
|
|
void ImageGeomSP::setViewportRange(simple_rect rect) {
|
|
|
if (rect == last_rect) [[likely]] return;
|
|
if (rect == last_rect) [[likely]] return;
|
|
|
last_rect = rect;
|
|
last_rect = rect;
|
|
|
- const auto vertex = (osg::Vec3Array *) getVertexArray();
|
|
|
|
|
|
|
+ const auto vertex = (Vec3Array *) getVertexArray();
|
|
|
assert(vertex->size() == image_vertex_num);
|
|
assert(vertex->size() == image_vertex_num);
|
|
|
auto [x, y, w, h] = rect;
|
|
auto [x, y, w, h] = rect;
|
|
|
vertex->at(0) = {x + 0, y + 0, 0};
|
|
vertex->at(0) = {x + 0, y + 0, 0};
|
|
@@ -119,20 +275,28 @@ void ImageGeomSP::setViewportRange(simple_rect rect) {
|
|
|
vertex->dirty();
|
|
vertex->dirty();
|
|
|
dirtyBound();
|
|
dirtyBound();
|
|
|
dirtyGLObjects();
|
|
dirtyGLObjects();
|
|
|
|
|
+
|
|
|
|
|
+ // disable depth test
|
|
|
|
|
+ getOrCreateStateSet()->setMode(GL_DEPTH_TEST,
|
|
|
|
|
+ StateAttribute::OVERRIDE | StateAttribute::OFF);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ImageGeomSP::setImageSP(const sp_image &img) {
|
|
void ImageGeomSP::setImageSP(const sp_image &img) {
|
|
|
- if (tex == nullptr
|
|
|
|
|
- || tex->getTextureWidth() != img.width()
|
|
|
|
|
- || tex->getTextureHeight() != img.height()) {
|
|
|
|
|
- const auto next_tex = new Texture2DSP();
|
|
|
|
|
- next_tex->setTextureSize(img.width(), img.height());
|
|
|
|
|
- next_tex->setInternalFormat(GL_RGBA);
|
|
|
|
|
- tex = next_tex;
|
|
|
|
|
|
|
+ upload_image_to_texture(img, tex);
|
|
|
|
|
+ getOrCreateStateSet()->setTextureAttributeAndModes(
|
|
|
|
|
+ 0, tex, StateAttribute::ON);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void ImageGeomSP::setRemapImage(const sp_image &img) {
|
|
|
|
|
+ upload_image_to_texture(img, remap_tex);
|
|
|
|
|
+ if (remap_tex) {
|
|
|
|
|
+ getOrCreateStateSet()->setTextureAttributeAndModes(
|
|
|
|
|
+ 1, remap_tex, StateAttribute::ON);
|
|
|
|
|
+ } else {
|
|
|
getOrCreateStateSet()->setTextureAttributeAndModes(
|
|
getOrCreateStateSet()->setTextureAttributeAndModes(
|
|
|
- 0, tex, osg::StateAttribute::ON);
|
|
|
|
|
|
|
+ 1, 0, StateAttribute::OFF);
|
|
|
}
|
|
}
|
|
|
- tex->setImageSP(img);
|
|
|
|
|
|
|
+ setup_program(this);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ImageGeomSP::setViewportRange(const float viewport_aspect,
|
|
void ImageGeomSP::setViewportRange(const float viewport_aspect,
|