if(ARB_texture_storage)
{
if(ARB_direct_state_access)
- glTextureStorage1D(id, self.levels, gl_fmt, self.width);
+ glTextureStorage1D(id, n_levels, gl_fmt, self.width);
else
{
bind_scratch();
- glTexStorage1D(target, self.levels, gl_fmt, self.width);
+ glTexStorage1D(target, n_levels, gl_fmt, self.width);
}
}
else
{
bind_scratch();
- glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, self.levels-1);
+ glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, n_levels-1);
GLenum comp = get_gl_components(get_components(storage_fmt));
GLenum type = get_gl_type(get_component_type(storage_fmt));
- for(unsigned i=0; i<self.levels; ++i)
+ for(unsigned i=0; i<n_levels; ++i)
{
unsigned lv_size = self.get_level_size(i);
glTexImage1D(target, i, gl_fmt, lv_size, 0, comp, type, 0);
size_t level_size = self.width*get_pixel_size(storage_fmt);
size_t total_size = level_size;
- for(unsigned i=0; i<self.levels; ++i, level_size>>=2)
+ for(unsigned i=0; i<n_levels; ++i, level_size>>=2)
total_size += level_size;
return total_size;
}
if(ARB_texture_storage)
{
if(ARB_direct_state_access)
- glTextureStorage2D(id, self.levels, gl_fmt, self.width, self.height);
+ glTextureStorage2D(id, n_levels, gl_fmt, self.width, self.height);
else
{
bind_scratch();
- glTexStorage2D(target, self.levels, gl_fmt, self.width, self.height);
+ glTexStorage2D(target, n_levels, gl_fmt, self.width, self.height);
}
}
else
{
bind_scratch();
- glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, self.levels-1);
+ glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, n_levels-1);
GLenum comp = get_gl_components(get_components(storage_fmt));
GLenum type = get_gl_type(get_component_type(storage_fmt));
- for(unsigned i=0; i<self.levels; ++i)
+ for(unsigned i=0; i<n_levels; ++i)
{
auto lv_size = self.get_level_size(i);
glTexImage2D(target, i, gl_fmt, lv_size.x, lv_size.y, 0, comp, type, 0);
size_t level_size = self.width*self.height*get_pixel_size(format);
size_t total_size = level_size;
- for(unsigned i=0; i<self.levels; ++i, level_size>>=2)
+ for(unsigned i=0; i<n_levels; ++i, level_size>>=2)
total_size += level_size;
return total_size;
}
size_t level_size = width*height*get_pixel_size(format);
size_t total_size = level_size;
- for(unsigned i=0; i<levels; ++i, level_size>>=2)
+ for(unsigned i=0; i<n_levels; ++i, level_size>>=2)
total_size += level_size*depth;
return total_size;
}
if(ARB_texture_storage)
{
if(ARB_direct_state_access)
- glTextureStorage3D(id, self.levels, gl_fmt, self.width, self.height, self.depth);
+ glTextureStorage3D(id, n_levels, gl_fmt, self.width, self.height, self.depth);
else
{
bind_scratch();
- glTexStorage3D(target, self.levels, gl_fmt, self.width, self.height, self.depth);
+ glTexStorage3D(target, n_levels, gl_fmt, self.width, self.height, self.depth);
}
}
else
bind_scratch();
GLenum comp = get_gl_components(get_components(storage_fmt));
GLenum type = get_gl_type(get_component_type(storage_fmt));
- for(unsigned i=0; i<self.levels; ++i)
+ for(unsigned i=0; i<n_levels; ++i)
{
auto lv_size = self.get_level_size(i);
glTexImage3D(target, i, gl_fmt, lv_size.x, lv_size.y, lv_size.z, 0, comp, type, 0);
}
- glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, self.levels-1);
+ glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, n_levels-1);
}
apply_swizzle();
size_t level_size = self.width*self.height*self.depth*get_pixel_size(format);
size_t total_size = level_size;
- for(unsigned i=0; i<self.levels; ++i, level_size>>=2)
+ for(unsigned i=0; i<n_levels; ++i, level_size>>=2)
total_size += level_size;
return total_size;
}
if(ARB_texture_storage)
{
if(ARB_direct_state_access)
- glTextureStorage2D(id, self.levels, gl_fmt, self.size, self.size);
+ glTextureStorage2D(id, n_levels, gl_fmt, self.size, self.size);
else
{
bind_scratch();
- glTexStorage2D(target, self.levels, gl_fmt, self.size, self.size);
+ glTexStorage2D(target, n_levels, gl_fmt, self.size, self.size);
}
}
else
bind_scratch();
GLenum comp = get_gl_components(get_components(storage_fmt));
GLenum type = get_gl_type(get_component_type(storage_fmt));
- for(unsigned i=0; i<self.levels; ++i)
+ for(unsigned i=0; i<n_levels; ++i)
{
unsigned lv_size = static_cast<const TextureCube *>(this)->get_level_size(i);
for(unsigned j=0; j<6; ++j)
glTexImage2D(get_gl_cube_face(j), i, gl_fmt, lv_size, lv_size, 0, comp, type, 0);
}
- glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, self.levels-1);
+ glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, n_levels-1);
}
apply_swizzle();
size_t level_size = self.size*self.size*get_pixel_size(storage_fmt);
size_t total_size = level_size;
- for(unsigned i=0; i<self.levels; ++i, level_size>>=2)
+ for(unsigned i=0; i<n_levels; ++i, level_size>>=2)
total_size += level_size;
return total_size;
}
void VulkanFramebuffer::prepare_image_layouts(bool discard) const
{
for(const Framebuffer::Attachment &a: static_cast<const Framebuffer *>(this)->attachments)
- a.tex->change_layout(0, a.level, get_vulkan_attachment_layout(get_components(a.tex->get_format())), discard);
+ a.tex->change_layout(a.level, get_vulkan_attachment_layout(get_components(a.tex->get_format())), discard);
}
void VulkanFramebuffer::set_debug_name(const string &name)
VkImageCreateInfo *image_info = static_cast<VkImageCreateInfo *>(ii);
image_info->imageType = VK_IMAGE_TYPE_1D;
image_info->extent.width = self.width;
- image_info->mipLevels = self.levels;
}
void VulkanTexture1D::sub_image(unsigned level, int x, unsigned wd, const void *data)
size_t data_size = wd*get_pixel_size(storage_fmt);
void *staging = device.get_transfer_queue().prepare_transfer(this, false, data_size,
[this, level, discard](){
- unsigned n_levels = static_cast<const Texture1D *>(this)->levels;
- change_layout(n_levels, level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
+ change_layout(level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
},
[this, level, x, wd](VkCommandBuffer cmd_buf, VkBuffer staging_buf, size_t src_off){
const VulkanFunctions &vk = device.get_functions();
stage_pixels(staging, data, wd);
}
-void VulkanTexture1D::generate_mipmap()
-{
- generate_mipmap_levels(static_cast<const Texture1D *>(this)->levels);
-}
-
void VulkanTexture1D::fill_mipmap_blit(unsigned level, void *b)
{
const Texture1D &self = *static_cast<const Texture1D *>(this);
virtual void fill_image_info(void *) const;
void sub_image(unsigned, int, unsigned, const void *);
- virtual void generate_mipmap();
virtual void fill_mipmap_blit(unsigned, void *);
public:
image_info->imageType = VK_IMAGE_TYPE_2D;
image_info->extent.width = self.width;
image_info->extent.height = self.height;
- image_info->mipLevels = self.levels;
}
void VulkanTexture2D::sub_image(unsigned level, int x, int y, unsigned wd, unsigned ht, const void *data)
size_t data_size = wd*ht*get_pixel_size(storage_fmt);
void *staging = device.get_transfer_queue().prepare_transfer(this, false, data_size,
[this, level, discard](){
- unsigned n_levels = static_cast<const Texture2D *>(this)->levels;
- change_layout(n_levels, level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
+ change_layout(level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
},
[this, level, x, y, wd, ht](VkCommandBuffer cmd_buf, VkBuffer staging_buf, size_t src_off){
const VulkanFunctions &vk = device.get_functions();
stage_pixels(staging, data, wd*ht);
}
-void VulkanTexture2D::generate_mipmap()
-{
- generate_mipmap_levels(static_cast<const Texture2D *>(this)->levels);
-}
-
void VulkanTexture2D::fill_mipmap_blit(unsigned level, void *b)
{
const Texture2D &self = *static_cast<const Texture2D *>(this);
virtual void fill_image_info(void *) const;
void sub_image(unsigned, int, int, unsigned, unsigned, const void *);
- virtual void generate_mipmap();
virtual void fill_mipmap_blit(unsigned, void *);
public:
image_info->imageType = VK_IMAGE_TYPE_2D;
image_info->extent.width = width;
image_info->extent.height = height;
- image_info->mipLevels = levels;
image_info->arrayLayers = depth;
}
image_info->extent.width = self.width;
image_info->extent.height = self.height;
image_info->extent.depth = self.depth;
- image_info->mipLevels = self.levels;
}
void VulkanTexture3D::sub_image(unsigned level, int x, int y, int z, unsigned wd, unsigned ht, unsigned dp, const void *data)
size_t data_size = wd*ht*dp*get_pixel_size(storage_fmt);
void *staging = device.get_transfer_queue().prepare_transfer(this, false, data_size,
[this, level, discard](){
- unsigned n_levels = static_cast<const Texture3D *>(this)->levels;
- change_layout(n_levels, level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
+ change_layout(level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
},
[this, level, x, y, z, wd, ht, dp](VkCommandBuffer cmd_buf, VkBuffer staging_buf, size_t src_off){
const VulkanFunctions &vk = device.get_functions();
stage_pixels(staging, data, wd*ht*dp);
}
-void VulkanTexture3D::generate_mipmap()
-{
- generate_mipmap_levels(static_cast<const Texture3D *>(this)->levels);
-}
-
void VulkanTexture3D::fill_mipmap_blit(unsigned level, void *b)
{
const Texture3D &self = *static_cast<const Texture3D *>(this);
virtual void fill_image_info(void *) const;
void sub_image(unsigned, int, int, int, unsigned, unsigned, unsigned, const void *);
- virtual void generate_mipmap();
virtual void fill_mipmap_blit(unsigned, void *);
bool is_array() const;
image_info.extent.width = 1;
image_info.extent.height = 1;
image_info.extent.depth = 1;
- image_info.mipLevels = 1;
+ image_info.mipLevels = self.n_levels;
image_info.arrayLayers = 1;
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
memory_id = device.get_allocator().allocate(handle, DEVICE_MEMORY);
// Trigger a layout transition if the image is used before uploading data.
- change_layout(0, -1, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, true);
+ change_layout(-1, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, true);
}
VkImageViewCreateInfo view_info = { };
}
}
-void VulkanTexture::generate_mipmap_levels(unsigned n_levels)
+void VulkanTexture::generate_mipmap()
{
+ unsigned n_levels = static_cast<const Texture *>(this)->n_levels;
+
TransferQueue &tq = device.get_transfer_queue();
for(unsigned i=0; i+1<n_levels; ++i)
{
tq.prepare_transfer(this, true, 0,
- [this, n_levels, i](){
- change_layout((i==0 ? n_levels : 0), i, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, false);
- change_layout(0, i+1, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true);
+ [this, i](){
+ change_layout(i, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, false);
+ change_layout(i+1, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true);
},
[this, i](VkCommandBuffer cmd_buf, VkBuffer, size_t){
const VulkanFunctions &vk = device.get_functions();
}
}
-void VulkanTexture::change_layout(unsigned n_levels, int level, unsigned layout, bool discard) const
+void VulkanTexture::change_layout(int level, unsigned layout, bool discard) const
{
- unsigned aspect = get_vulkan_aspect(get_components(static_cast<const Texture *>(this)->storage_fmt));
- if(n_levels>0)
- device.get_synchronizer().split_image_mipmap(handle, aspect, n_levels);
+ const Texture &self = *static_cast<const Texture *>(this);
+
+ unsigned aspect = get_vulkan_aspect(get_components(self.storage_fmt));
+ if(level>=0)
+ device.get_synchronizer().split_image_mipmap(handle, aspect, self.n_levels);
device.get_synchronizer().change_image_layout(handle, aspect, level, layout, discard);
}
void stage_pixels(void *, const void *, size_t);
- virtual void generate_mipmap() = 0;
- void generate_mipmap_levels(unsigned);
+ void generate_mipmap();
virtual void fill_mipmap_blit(unsigned, void *) = 0;
- void change_layout(unsigned, int, unsigned, bool) const;
+ void change_layout(int, unsigned, bool) const;
void set_debug_name(const std::string &);
void set_vulkan_object_names() const;
image_info->imageType = VK_IMAGE_TYPE_2D;
image_info->extent.width = self.size;
image_info->extent.height = self.size;
- image_info->mipLevels = self.levels;
image_info->arrayLayers = 6;
}
size_t data_size = wd*ht*get_pixel_size(storage_fmt);
void *staging = device.get_transfer_queue().prepare_transfer(this, false, data_size,
[this, level, discard](){
- unsigned n_levels = static_cast<const TextureCube *>(this)->levels;
- change_layout(n_levels, level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
+ change_layout(level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
},
[this, face, level, x, y, wd, ht](VkCommandBuffer cmd_buf, VkBuffer staging_buf, size_t src_off){
const VulkanFunctions &vk = device.get_functions();
stage_pixels(staging, data, wd*ht);
}
-void VulkanTextureCube::generate_mipmap()
-{
- generate_mipmap_levels(static_cast<const TextureCube *>(this)->levels);
-}
-
void VulkanTextureCube::fill_mipmap_blit(unsigned level, void *b)
{
const TextureCube &self = *static_cast<const TextureCube *>(this);
virtual void fill_image_info(void *) const;
void sub_image(unsigned, unsigned, int, int, unsigned, unsigned, const void *);
- virtual void generate_mipmap();
virtual void fill_mipmap_blit(unsigned, void *);
public:
swizzle = swiz;
}
+unsigned Texture::count_levels(unsigned size)
+{
+ unsigned n = 0;
+ for(; size; size>>=1, ++n) ;
+ return n;
+}
+
void Texture::load_image(const string &fn, unsigned lv)
{
Graphics::Image img;
PixelFormat format = NO_PIXELFORMAT;
PixelFormat storage_fmt = NO_PIXELFORMAT;
ComponentSwizzle swizzle = NO_SWIZZLE;
+ unsigned n_levels = 0;
bool use_srgb_format = false;
bool auto_gen_mipmap = false;
Texture(unsigned);
void set_format(PixelFormat);
+ static unsigned count_levels(unsigned);
public:
PixelFormat get_format() const { return format; }
{
if(width>0)
{
- if(fmt!=format || wd!=width || (lv && lv!=levels))
+ if(fmt!=format || wd!=width || (lv && lv!=n_levels))
throw incompatible_data("Texture1D::storage");
return;
}
set_format(fmt);
width = wd;
- levels = get_n_levels();
+ n_levels = count_levels(width);
if(lv)
- levels = min(levels, lv);
+ n_levels = min(n_levels, lv);
allocate();
}
{
if(width==0)
throw invalid_operation("Texture1D::sub_image");
- if(level>=levels || x>width || x+wd>width)
+ if(level>=n_levels || x>width || x+wd>width)
throw out_of_range("Texture1D::sub_image");
Texture1DBackend::sub_image(level, x, wd, data);
image(0, img.get_pixels());
}
-unsigned Texture1D::get_n_levels() const
-{
- unsigned n = 0;
- for(unsigned s=width; s; s>>=1, ++n) ;
- return n;
-}
-
unsigned Texture1D::get_level_size(unsigned level) const
{
return width>>level;
private:
unsigned width = 0;
- unsigned levels = 0;
public:
/** Sets storage format and size and allocates memory for the texture. If
unsigned get_width() const { return width; }
private:
- unsigned get_n_levels() const;
unsigned get_level_size(unsigned) const;
};
{
if(width>0)
{
- if(fmt!=format || wd!=width || ht!=height || (lv && lv!=levels))
+ if(fmt!=format || wd!=width || ht!=height || (lv && lv!=n_levels))
throw incompatible_data("Texture2D::storage");
return;
}
set_format(fmt);
width = wd;
height = ht;
- levels = get_n_levels();
+ n_levels = count_levels(max(width, height));
if(lv>0)
- levels = min(levels, lv);
+ n_levels = min(n_levels, lv);
allocate();
}
{
if(width==0 || height==0)
throw invalid_operation("Texture2D::sub_image");
- if(level>=levels || x>width || x+wd>width || y>height || y+ht>height)
+ if(level>=n_levels || x>width || x+wd>width || y>height || y+ht>height)
throw out_of_range("Texture2D::sub_image");
Texture2DBackend::sub_image(level, x, y, wd, ht, data);
image(0, img.get_pixels());
}
-unsigned Texture2D::get_n_levels() const
-{
- unsigned n = 0;
- for(unsigned s=max(width, height); s; s>>=1, ++n) ;
- return n;
-}
-
LinAl::Vector<unsigned, 2> Texture2D::get_level_size(unsigned level) const
{
unsigned w = width>>level;
private:
unsigned width = 0;
unsigned height = 0;
- unsigned levels = 0;
public:
Texture2D() = default;
void Texture2DArray::layer_image(unsigned level, unsigned z, const void *data)
{
- if(level>=levels || z>=depth)
+ if(level>=n_levels || z>=depth)
throw out_of_range("Texture2DArray::layer_image");
LinAl::Vector<unsigned, 3> size = get_level_size(level);
{
if(width>0)
{
- if(fmt!=format || wd!=width || ht!=height || dp!=depth || (lv && lv!=levels))
+ if(fmt!=format || wd!=width || ht!=height || dp!=depth || (lv && lv!=n_levels))
throw incompatible_data("Texture3D::storage");
return;
}
width = wd;
height = ht;
depth = dp;
- levels = get_n_levels();
+ unsigned size = max(width, height);
+ if(!is_array())
+ size = max(size, depth);
+ n_levels = count_levels(size);
if(lv>0)
- levels = min(levels, lv);
+ n_levels = min(n_levels, lv);
allocate();
}
{
if(width==0 || height==0 || depth==0)
throw invalid_operation("Texture3D::sub_image");
- if(level>=levels || x>width || x+wd>width || y>height || y+ht>height || z>depth || z+dp>depth)
+ if(level>=n_levels || x>width || x+wd>width || y>height || y+ht>height || z>depth || z+dp>depth)
throw out_of_range("Texture3D::sub_image");
Texture3DBackend::sub_image(level, x, y, z, wd, ht, dp, data);
image(0, img.get_pixels());
}
-unsigned Texture3D::get_n_levels() const
-{
- unsigned s = max(width, height);
- if(!is_array())
- s = max(s, depth);
- unsigned n = 0;
- for(; s; s>>=1, ++n) ;
- return n;
-}
-
LinAl::Vector<unsigned, 3> Texture3D::get_level_size(unsigned level) const
{
unsigned w = width>>level;
unsigned width = 0;
unsigned height = 0;
unsigned depth = 0;
- unsigned levels = 0;
Texture3D(unsigned);
public:
unsigned get_height() const { return height; }
unsigned get_depth() const { return depth; }
protected:
- unsigned get_n_levels() const;
LinAl::Vector<unsigned, 3> get_level_size(unsigned) const;
};
{
if(size>0)
{
- if(fmt!=format || sz!=size || (lv && lv!=levels))
+ if(fmt!=format || sz!=size || (lv && lv!=n_levels))
throw incompatible_data("TextureCube::storage");
return;
}
set_format(fmt);
size = sz;
- levels = get_n_levels();
+ n_levels = count_levels(size);
if(lv>0)
- levels = min(levels, lv);
+ n_levels = min(n_levels, lv);
allocate();
}
{
if(size==0)
throw invalid_operation("TextureCube::sub_image");
- if(level>=levels || x>size || x+wd>size || y>size || y+ht>size)
+ if(level>=n_levels || x>size || x+wd>size || y>size || y+ht>size)
throw out_of_range("TextureCube::sub_image");
TextureCubeBackend::sub_image(face, level, x, y, wd, ht, data);
image(0, img.get_pixels());
}
-unsigned TextureCube::get_n_levels() const
-{
- unsigned n = 0;
- for(unsigned s=size; s; s>>=1, ++n) ;
- return n;
-}
-
unsigned TextureCube::get_level_size(unsigned level) const
{
return size>>level;
private:
unsigned size = 0;
- unsigned levels = 0;
static const Vector3 directions[6];
static const unsigned orientations[12];
unsigned get_size() const { return size; }
private:
- unsigned get_n_levels() const;
unsigned get_level_size(unsigned) const;
public: