#include <msp/gl/extensions/ext_framebuffer_object.h>
#include <msp/gl/extensions/ext_gpu_shader4.h>
#include <msp/gl/extensions/ext_texture_array.h>
+#include <msp/gl/extensions/ext_texture_filter_anisotropic.h>
#include <msp/gl/extensions/msp_clipping.h>
#include <msp/gl/extensions/nv_fbo_color_attachments.h>
#include "deviceinfo.h"
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, reinterpret_cast<int *>(&max_uniform_bindings));
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, reinterpret_cast<int *>(&uniform_buffer_alignment));
}
+ if(EXT_texture_filter_anisotropic)
+ glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &max_anisotropy);
}
{
if(size==0)
throw invalid_operation("Buffer::sub_data");
+ if(off>size || off+sz>size)
+ throw out_of_range("Buffer::sub_data");
BufferBackend::sub_data(off, sz, d);
}
unsigned max_samples = 4;
unsigned max_uniform_bindings = 24;
unsigned uniform_buffer_alignment = 256;
+ float max_anisotropy = 1.0f;
Limits();
};
#include <msp/strings/format.h>
+#include "deviceinfo.h"
#include "error.h"
#include "sampler.h"
void Sampler::set_mag_filter(TextureFilter f)
{
+ if(is_mipmapped(f))
+ throw invalid_argument("Sampler::set_mag_filter");
mag_filter = f;
dirty_params |= MAG_FILTER;
}
{
if(a<1.0f)
throw invalid_argument("Sampler::set_max_anisotropy");
+ if(a>DeviceInfo::get_global().limits.max_anisotropy)
+ throw out_of_range("Sampler::set_max_anisotropy");
bool supported = check_anisotropic(a>1.0f);
max_anisotropy = a;
if(supported)
return sub_image(level, 0, get_level_size(level), data);
}
-void Texture1D::sub_image(unsigned level, int x, unsigned wd, const void *data)
+void Texture1D::sub_image(unsigned level, unsigned x, unsigned wd, const void *data)
{
if(width==0)
throw invalid_operation("Texture1D::sub_image");
- if(level>=levels)
+ if(level>=levels || x>width || x+wd>width)
throw out_of_range("Texture1D::sub_image");
Texture1DBackend::sub_image(level, x, wd, data);
/** Replaces a range of texels in the texture. Allocated storage must
exist. The image data is interpreted according to the storage format and
the range must be fully inside the selected mipmap level. */
- void sub_image(unsigned level, int x, unsigned wd, const void *);
+ void sub_image(unsigned level, unsigned x, unsigned wd, const void *);
virtual void image(const Graphics::Image &, unsigned = 0);
return sub_image(level, 0, 0, size.x, size.y, data);
}
-void Texture2D::sub_image(unsigned level, int x, int y, unsigned wd, unsigned ht, const void *data)
+void Texture2D::sub_image(unsigned level, unsigned x, unsigned y, unsigned wd, unsigned ht, const void *data)
{
if(width==0 || height==0)
throw invalid_operation("Texture2D::sub_image");
- if(level>=levels)
+ if(level>=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);
/** Replaces a rectangular region of the texture. Allocated storage must
exist. The image data is interpreted according to the storage format and
the region must be fully inside the selected mipmap level. */
- void sub_image(unsigned level, int x, int y, unsigned wd, unsigned ht, const void *);
+ void sub_image(unsigned level, unsigned x, unsigned y, unsigned wd, unsigned ht, const void *);
virtual void image(const Graphics::Image &, unsigned = 0);
return sub_image(level, 0, 0, 0, size.x, size.y, size.z, data);
}
-void Texture3D::sub_image(unsigned level, int x, int y, int z, unsigned wd, unsigned ht, unsigned dp, const void *data)
+void Texture3D::sub_image(unsigned level, unsigned x, unsigned y, unsigned z, unsigned wd, unsigned ht, unsigned dp, const void *data)
{
if(width==0 || height==0 || depth==0)
throw invalid_operation("Texture3D::sub_image");
- if(level>=levels)
+ if(level>=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);
/** Replaces a cuboid-shaped region of the texture. Allocated storage must
exist. The image data is interpreted according to the storage format and
the region must be fully inside the texture. */
- void sub_image(unsigned level, int x, int y, int z, unsigned wd, unsigned ht, unsigned dp, const void *);
+ void sub_image(unsigned level, unsigned x, unsigned y, unsigned z, unsigned wd, unsigned ht, unsigned dp, const void *);
/** Sets the texture's contents from an image. The image is treated as a
stack of square layers and its height must be divisible by its width. If
return sub_image(face, level, 0, 0, lsz, lsz, data);
}
-void TextureCube::sub_image(TextureCubeFace face, unsigned level, int x, int y, unsigned wd, unsigned ht, const void *data)
+void TextureCube::sub_image(TextureCubeFace face, unsigned level, unsigned x, unsigned y, unsigned wd, unsigned ht, const void *data)
{
if(size==0)
throw invalid_operation("TextureCube::sub_image");
- if(level>=levels)
+ if(level>=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);
/** Replaces a rectangular region of a face. Allocated storage must exist.
The image data is interpreted according to the storage format and the region
must be fully inside the face. */
- void sub_image(TextureCubeFace, unsigned level, int x, int y, unsigned w, unsigned h, const void *);
+ void sub_image(TextureCubeFace, unsigned level, unsigned x, unsigned y, unsigned w, unsigned h, const void *);
void image(TextureCubeFace, const Graphics::Image &);