]> git.tdb.fi Git - libs/gl.git/blob - source/backends/opengl/texture2d_backend.cpp
Move all OpenGL-specific code to a separate directory
[libs/gl.git] / source / backends / opengl / texture2d_backend.cpp
1 #include <msp/gl/extensions/arb_direct_state_access.h>
2 #include <msp/gl/extensions/arb_texture_storage.h>
3 #include <msp/gl/extensions/arb_vertex_buffer_object.h>
4 #include <msp/graphics/imageloader.h>
5 #include "buffer.h"
6 #include "gl.h"
7 #include "texture2d.h"
8 #include "texture2d_backend.h"
9
10 namespace Msp {
11 namespace GL {
12
13 class OpenGLTexture2D::AsyncLoader: public Resource::AsyncLoader
14 {
15 private:
16         Texture2D &texture;
17         IO::Seekable &io;
18         Buffer pixel_buffer;
19         char *mapped_address;
20         Graphics::Image image;
21         Graphics::ImageLoader *img_loader;
22         unsigned n_bytes;
23         int phase;
24
25 public:
26         AsyncLoader(Texture2D &, IO::Seekable &);
27         ~AsyncLoader();
28
29         virtual bool needs_sync() const;
30         virtual bool process();
31 };
32
33
34 OpenGLTexture2D::OpenGLTexture2D(ResourceManager *m):
35         Texture(GL_TEXTURE_2D, m)
36 { }
37
38 void OpenGLTexture2D::allocate()
39 {
40         unsigned width = static_cast<const Texture2D *>(this)->width;
41         unsigned height = static_cast<const Texture2D *>(this)->height;
42         unsigned levels = static_cast<const Texture2D *>(this)->levels;
43
44         GLenum gl_fmt = get_gl_pixelformat(storage_fmt);
45         if(ARB_texture_storage)
46         {
47                 if(ARB_direct_state_access)
48                         glTextureStorage2D(id, levels, gl_fmt, width, height);
49                 else
50                 {
51                         bind_scratch();
52                         glTexStorage2D(target, levels, gl_fmt, width, height);
53                 }
54         }
55         else
56         {
57                 bind_scratch();
58                 glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels-1);
59                 GLenum comp = get_gl_components(get_components(storage_fmt));
60                 GLenum type = get_gl_type(get_component_type(storage_fmt));
61                 for(unsigned i=0; i<levels; ++i)
62                 {
63                         auto lv_size = static_cast<const Texture2D *>(this)->get_level_size(i);
64                         glTexImage2D(target, i, gl_fmt, lv_size.x, lv_size.y, 0, comp, type, 0);
65                 }
66         }
67
68         apply_swizzle();
69 }
70
71 void OpenGLTexture2D::sub_image(unsigned level, int x, int y, unsigned wd, unsigned ht, const void *data)
72 {
73         GLenum comp = get_gl_components(get_components(storage_fmt));
74         GLenum type = get_gl_type(get_component_type(storage_fmt));
75         if(ARB_direct_state_access)
76                 glTextureSubImage2D(id, level, x, y, wd, ht, comp, type, data);
77         else
78         {
79                 bind_scratch();
80                 glTexSubImage2D(target, level, x, y, wd, ht, comp, type, data);
81         }
82 }
83
84 void OpenGLTexture2D::sub_image(unsigned level, int x, int y, unsigned wd, unsigned ht, const Buffer &buffer, unsigned offset)
85 {
86         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer.id);
87         sub_image(level, x, y, wd, ht, reinterpret_cast<void *>(offset));
88         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
89 }
90
91 Resource::AsyncLoader *OpenGLTexture2D::create_async_loader(IO::Seekable &io)
92 {
93         return new AsyncLoader(static_cast<Texture2D &>(*this), io);
94 }
95
96 void OpenGLTexture2D::unload()
97 {
98         glDeleteTextures(1, &id);
99         id = 0;
100 }
101
102
103 OpenGLTexture2D::AsyncLoader::AsyncLoader(Texture2D &t, IO::Seekable &i):
104         texture(t),
105         io(i),
106         mapped_address(0),
107         img_loader(Graphics::ImageLoader::open_io(io)),
108         phase(0)
109 { }
110
111 OpenGLTexture2D::AsyncLoader::~AsyncLoader()
112 {
113         if(mapped_address)
114                 pixel_buffer.unmap();
115         delete img_loader;
116 }
117
118 bool OpenGLTexture2D::AsyncLoader::needs_sync() const
119 {
120         return phase%2;
121 }
122
123 bool OpenGLTexture2D::AsyncLoader::process()
124 {
125         if(phase==0)
126         {
127                 image.load_headers(*img_loader);
128                 n_bytes = image.get_stride()*image.get_height();
129         }
130         else if(phase==1)
131         {
132                 pixel_buffer.storage(n_bytes);
133                 mapped_address = reinterpret_cast<char *>(pixel_buffer.map());
134         }
135         else if(phase==2)
136                 image.load_into(*img_loader, mapped_address);
137         else if(phase==3)
138         {
139                 mapped_address = 0;
140                 if(!pixel_buffer.unmap())
141                 {
142                         phase = 1;
143                         return false;
144                 }
145
146                 if(!texture.id)
147                         texture.generate_id();
148
149                 unsigned w = image.get_width();
150                 unsigned h = image.get_height();
151                 texture.storage(pixelformat_from_image(image, texture.use_srgb_format), w, h);
152                 texture.OpenGLTexture2D::sub_image(0, 0, 0, w, h, pixel_buffer, 0);
153
154                 if(texture.auto_gen_mipmap)
155                         texture.generate_mipmap();
156         }
157
158         ++phase;
159         return phase>3;
160 }
161
162 } // namespace GL
163 } // namespace Msp