Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 4 of 4

Thread: AMD bug with samplers

  1. #1
    Junior Member Regular Contributor
    Join Date
    Apr 2004
    Posts
    205

    AMD bug with samplers

    Its a bit involved to explain but bear with me.
    The setup is as follows:
    - single texture bound to 2 different texture units (say 0 and 1)
    - 2 sampler objects, one for each tex unit and bound to them.
    - the sampler objects have different sampling states, say 0 has mag filter LINEAR and 1 has mag filter NEAREST.
    - a fragment shader uses both samplers to fetch the (same) texture.

    Then the fetched data from the 2 samplers use the sampling states from only one of the sampler objects - both are either LINEAR or NEAREST. I'm not sure how the choice is made, maybe the sampler object which was set latest is used.

    here is simple win32-based code to reproduce the bug
    to display the result, the fragment shader outputs sample0 to the red channel and sample1 to the green channel - one of them should be filtered and the other not, but they are both the same.

    Code :
    #include <windows.h>
    #include <GL/gl.h>
    #include "glext.h"
     
    #define OGLENTRY __stdcall
     
    void (OGLENTRY *_glEnableVertexAttribArray) (GLuint index);
    void (OGLENTRY *_glVertexAttribPointer) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
    void (OGLENTRY *_glBufferData) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
    void (OGLENTRY *_glBindBufferBase) (GLenum target, GLuint index, GLuint buffer);
    void (OGLENTRY *_glGenBuffers) (GLsizei n, GLuint *buffers);
    void (OGLENTRY *_glSamplerParameteri) (GLuint sampler, GLenum pname, GLint param);
    void (OGLENTRY *_glBindSampler) (GLuint unit, GLuint sampler);
    GLuint (OGLENTRY *_glCreateShader) (GLenum type);
    void (OGLENTRY *_glShaderSource) (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length);
    void (OGLENTRY *_glCompileShader) (GLuint shader);
    void (OGLENTRY *_glGetShaderiv) (GLuint shader, GLenum pname, GLint *params);
    GLuint (OGLENTRY *_glCreateProgram) (void);
    void (OGLENTRY *_glAttachShader) (GLuint program, GLuint shader);
    void (OGLENTRY *_glLinkProgram) (GLuint program);
    void (OGLENTRY *_glGetProgramiv) (GLuint program, GLenum pname, GLint *params);
    void (OGLENTRY *_glUseProgram) (GLuint program);
    GLint (OGLENTRY *_glGetUniformLocation) (GLuint program, const GLchar *name);
    void (OGLENTRY *_glUniform1i) (GLint location, GLint v0);
    void (OGLENTRY *_glActiveTexture) (GLenum texture);
    void (OGLENTRY *_glGenSamplers) (GLsizei count, GLuint *samplers);
    void (OGLENTRY *_glBindBuffer) (GLenum target, GLuint buffer);
    void (OGLENTRY *_glGetShaderInfoLog) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
    void (OGLENTRY *_glGetProgramInfoLog) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
     
     
    void init()
    {
    	static const char vs_text[] =
    		"#version 330\n"
    		"layout(location=0) in vec2 a2v_pos;\n"
    		"layout(location=1) in vec2 a2v_tc;\n"
    		"out vec2 v2f_tc;\n"
    		"void main() {\n"
    		"	v2f_tc = a2v_tc;\n"
    		"	gl_Position = vec4(a2v_pos, 0, 1);\n"
    		"}";
     
    	static const char fs_text[] =
    		"#version 330\n"
    		"uniform sampler2D s0, s1;\n"
    		"in vec2 v2f_tc;\n"
    		"layout(location=0) out vec4 c0;\n"
    		"void main() {\n"
    		"	vec4 f0 = texture(s0, v2f_tc);\n"
    		"	vec4 f1 = texture(s1, v2f_tc);\n"
    		"	c0 = vec4(f0.x, f1.x, 0, 0);\n"
    		"}";
     
    	static const short image[] = {
    		0, -1, 0, -1,
    		-1, 0, -1, 0,
    		0, -1, 0, -1,
    		-1, 0, -1, 0,
    	};
     
    	static const struct { float x, y, s, t; } verts[4] = {
    		-1, -1, 0, 0,
    		+1, -1, 1, 0,
    		-1, +1, 0, 1,
    		+1, +1, 1, 1,
    	};
     
    	GLenum status;
    	GLint len, i;
    	GLuint vs, fs, prog, tex, sam[2], vb;
    	const char *txt;
     
     
    	#define GET(f) *(void **)&amp;_ ## f = wglGetProcAddress( # f )
    	GET(glEnableVertexAttribArray);
    	GET(glVertexAttribPointer);
    	GET(glBufferData);
    	GET(glBindBufferBase);
    	GET(glGenBuffers);
    	GET(glSamplerParameteri);
    	GET(glBindSampler);
    	GET(glCreateShader);
    	GET(glShaderSource);
    	GET(glCompileShader);
    	GET(glGetShaderiv);
    	GET(glCreateProgram);
    	GET(glAttachShader);
    	GET(glLinkProgram);
    	GET(glGetProgramiv);
    	GET(glUseProgram);
    	GET(glGetUniformLocation);
    	GET(glUniform1i);
    	GET(glActiveTexture);
    	GET(glGenSamplers);
    	GET(glBindBuffer);
    	GET(glGetShaderInfoLog);
    	GET(glGetProgramInfoLog);
     
     
    	vs = _glCreateShader(GL_VERTEX_SHADER);
    	txt = vs_text;
    	len = sizeof(vs_text);
    	_glShaderSource(vs, 1, &amp;txt, &amp;len);
    	_glCompileShader(vs);
    	_glGetShaderiv(vs, GL_COMPILE_STATUS, &amp;status);
    	if (status == GL_FALSE) _asm int 3
     
    	fs = _glCreateShader(GL_FRAGMENT_SHADER);
    	txt = fs_text;
    	len = sizeof(fs_text);
    	_glShaderSource(fs, 1, &amp;txt, &amp;len);
    	_glCompileShader(fs);
    	_glGetShaderiv(fs, GL_COMPILE_STATUS, &amp;status);
    	if (status == GL_FALSE) {
    		char log[65536];
    		GLint log_size;
    		_glGetShaderInfoLog(fs, sizeof(log), &amp;log_size, log);
    		_asm int 3
    	}
     
    	prog = _glCreateProgram();
    	_glAttachShader(prog, vs);
    	_glAttachShader(prog, fs);
    	_glLinkProgram(prog);
    	_glGetProgramiv(prog, GL_LINK_STATUS, &amp;status);
    	if (status == GL_FALSE) {
    		char log[65536];
    		GLint log_size;
    		_glGetProgramInfoLog(prog, sizeof(log), &amp;log_size, log);
    		_asm int 3
    	}	
     
    	_glUseProgram(prog);
    	i = _glGetUniformLocation(prog, "s0");
    	if (i < 0) _asm int 3
    	_glUniform1i(i, 0);
    	i = _glGetUniformLocation(prog, "s1");
    	if (i < 0) _asm int 3
    	_glUniform1i(i, 1);
     
    	// create texture and bind to sampler 0
    	glGenTextures(1, &amp;tex);
    	glBindTexture(GL_TEXTURE_2D, tex);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
    	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5, 4, 4, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, image);
     
    	// bind the texture to sampler 1 too
    	_glActiveTexture(GL_TEXTURE1);
    	glBindTexture(GL_TEXTURE_2D, tex);
     
    	_glGenSamplers(2, sam);
    	_glBindSampler(0, sam[0]);
    	_glBindSampler(1, sam[1]);
    	_glSamplerParameteri(sam[0], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    	_glSamplerParameteri(sam[1], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     
    	_glGenBuffers(1, &amp;vb);
    	_glBindBuffer(GL_ARRAY_BUFFER, vb);
    	_glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
    	_glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(verts[0]), NULL);
    	_glEnableVertexAttribArray(0);
    	_glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(verts[0]), (char *)NULL + 2*sizeof(float));
    	_glEnableVertexAttribArray(1);
     
    	if (glGetError()) _asm int 3
    }
     
    int run;
    LRESULT CALLBACK wnd_proc(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
    {
    	switch (msg) {
    	case WM_PAINT: ValidateRect(wnd, NULL); return 0;
    	case WM_CLOSE: run = 0; return 0;
    	default: return DefWindowProcA(wnd, msg, wp, lp);
    	}
    }
     
    int CALLBACK WinMain(HINSTANCE inst, HINSTANCE prev_inst, char *cl, int cs)
    {
    	WNDCLASSA wc;
    	HWND wnd;
    	HDC dc;
    	PIXELFORMATDESCRIPTOR pfd;
    	int pf;
    	HGLRC rc;
     
    	memset(&amp;wc, 0, sizeof(wc));
    	wc.hInstance = inst;
    	wc.lpfnWndProc = wnd_proc;
    	wc.lpszClassName = "_test_class_name";
    	RegisterClassA(&amp;wc);
    	wnd = CreateWindowExA(0, wc.lpszClassName, NULL, WS_SYSMENU, 100, 100, 256, 196, NULL, NULL, NULL, NULL);
    	ShowWindow(wnd, SW_SHOW);
    	dc = GetDC(wnd);
    	memset(&amp;pfd, 0, sizeof(pfd));
    	pfd.nSize = sizeof(pdf);
    	pfd.nVersion = 1;
    	pfd.dwFlags = PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DEPTH_DONTCARE;
    	pf = ChoosePixelFormat(dc, &amp;pfd);
    	SetPixelFormat(dc, pf, NULL);
    	rc = wglCreateContext(dc);
    	wglMakeCurrent(dc, rc);
    	init();
     
    	run = 1;
    	while (run) {
    		MSG msg;
    		while (PeekMessageA(&amp;msg, NULL, 0, 0, PM_REMOVE))
    			DispatchMessageA(&amp;msg);
     
    		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    		glFinish();
    		Sleep(100);
    	}
     
    	return 0;
    }


    by the way this is not a regression for 11.12, it is present in the older drivers too


    I imagine this is some kind of optimization from the pre-sampler-object time which collapses samplers when they have the same texture bound and which was not updated to take into account the new sampler objects.

  2. #2
    Junior Member Regular Contributor
    Join Date
    Apr 2004
    Posts
    205

    Re: AMD bug with samplers

    this bug is not present on nvidia. there the sample code works correctly - the red channel is filtered (linear) and the green is not (nearest).

    ah, there is a minor compile error in the above code:
    "pfd.nSize = sizeof(pdf);" should be "pfd.nSize = sizeof(pfd);" instead

  3. #3
    Intern Newbie
    Join Date
    Sep 2011
    Posts
    32

    Re: AMD bug with samplers

    Oops, I was just about to do the same thing for my toy app, a filtering comparison demo. Let me check if I ran into the same problem. ;-)
    Senior Engineer, OpenGL driver, AMD

  4. #4
    Junior Member Regular Contributor
    Join Date
    Apr 2004
    Posts
    205

    Re: AMD bug with samplers

    Great! Can I take this as an indication the bug will be fixed soon?


    Im joking. This is not really a showstopper bug, i think we can live with it. But still it would be nice to be fixed if its not too much trouble

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •