1 #include <msp/datafile/rawdata.h>
2 #include <msp/gl/extensions/arb_direct_state_access.h>
3 #include <msp/gl/extensions/arb_texture_storage.h>
4 #include <msp/gl/extensions/arb_vertex_buffer_object.h>
5 #include <msp/graphics/imageloader.h>
9 #include "texture2d_backend.h"
16 class OpenGLTexture2D::AsyncLoader: public Resource::AsyncLoader
21 Texture2D::AsyncTransfer transfer;
22 Graphics::Image image;
23 Graphics::ImageLoader *img_loader = 0;
24 DataFile::RawData *raw_data = 0;
29 AsyncLoader(Texture2D &, IO::Seekable &);
32 virtual bool needs_sync() const;
33 virtual bool process();
37 OpenGLTexture2D::OpenGLTexture2D():
38 Texture(GL_TEXTURE_2D)
41 void OpenGLTexture2D::allocate()
43 const Texture2D &self = *static_cast<const Texture2D *>(this);
48 GLenum gl_fmt = get_gl_pixelformat(storage_fmt);
49 if(ARB_texture_storage)
51 if(ARB_direct_state_access)
52 glTextureStorage2D(id, n_levels, gl_fmt, self.width, self.height);
56 glTexStorage2D(target, n_levels, gl_fmt, self.width, self.height);
62 glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, n_levels-1);
63 GLenum comp = get_gl_components(get_components(storage_fmt));
64 GLenum type = get_gl_type(get_component_type(storage_fmt));
65 for(unsigned i=0; i<n_levels; ++i)
67 auto lv_size = self.get_level_size(i);
68 glTexImage2D(target, i, gl_fmt, lv_size.x, lv_size.y, 0, comp, type, 0);
75 void OpenGLTexture2D::sub_image(unsigned level, int x, int y, unsigned wd, unsigned ht, const void *data)
77 GLenum comp = get_gl_components(get_components(storage_fmt));
78 GLenum type = get_gl_type(get_component_type(storage_fmt));
79 if(ARB_direct_state_access)
80 glTextureSubImage2D(id, level, x, y, wd, ht, comp, type, data);
84 glTexSubImage2D(target, level, x, y, wd, ht, comp, type, data);
88 Resource::AsyncLoader *OpenGLTexture2D::load(IO::Seekable &io, const Resources *)
90 return new AsyncLoader(static_cast<Texture2D &>(*this), io);
93 uint64_t OpenGLTexture2D::get_data_size() const
98 const Texture2D &self = *static_cast<const Texture2D *>(this);
100 size_t level_size = self.width*self.height*get_pixel_size(format);
101 size_t total_size = level_size;
102 for(unsigned i=0; i<n_levels; ++i, level_size>>=2)
103 total_size += level_size;
107 void OpenGLTexture2D::unload()
109 glDeleteTextures(1, &id);
114 OpenGLTexture2D::AsyncTransfer::AsyncTransfer(AsyncTransfer &&other):
115 pixel_buffer(other.pixel_buffer)
117 other.pixel_buffer = 0;
120 OpenGLTexture2D::AsyncTransfer &OpenGLTexture2D::AsyncTransfer::operator=(AsyncTransfer &&other)
123 pixel_buffer = other.pixel_buffer;
124 other.pixel_buffer = 0;
129 OpenGLTexture2D::AsyncTransfer::~AsyncTransfer()
134 void *OpenGLTexture2D::AsyncTransfer::allocate()
136 const Texture2D::AsyncTransfer &self = *static_cast<const Texture2D::AsyncTransfer *>(this);
138 pixel_buffer = new Buffer;
139 pixel_buffer->storage(self.data_size, STREAMING);
140 return pixel_buffer->map();
143 void OpenGLTexture2D::AsyncTransfer::finalize()
145 const Texture2D::AsyncTransfer &self = *static_cast<const Texture2D::AsyncTransfer *>(this);
147 pixel_buffer->unmap();
149 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixel_buffer->id);
150 self.texture->OpenGLTexture2D::sub_image(self.level, self.x, self.y, self.width, self.height, 0);
151 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
155 OpenGLTexture2D::AsyncLoader::AsyncLoader(Texture2D &t, IO::Seekable &i):
161 io.seek(0, IO::S_BEG);
163 if(DataFile::RawData::detect_signature(string(magic, 4)))
165 raw_data = new DataFile::RawData;
166 raw_data->open_io(io, "async");
169 img_loader = Graphics::ImageLoader::open_io(io);
172 OpenGLTexture2D::AsyncLoader::~AsyncLoader()
178 bool OpenGLTexture2D::AsyncLoader::needs_sync() const
183 bool OpenGLTexture2D::AsyncLoader::process()
188 n_bytes = raw_data->get_size();
191 image.load_headers(*img_loader);
192 n_bytes = image.get_stride()*image.get_height();
199 unsigned w = image.get_width();
200 unsigned h = image.get_height();
201 texture.storage(pixelformat_from_image(image, texture.use_srgb_format), w, h);
204 transfer = texture.sub_image_async(0, 0, 0, texture.width, texture.height);
209 raw_data->load_into(transfer.get_address());
211 image.load_into(*img_loader, transfer.get_address());
215 transfer = Texture2D::AsyncTransfer();
217 if(texture.auto_gen_mipmap)
218 texture.generate_mipmap();