| Summary: | GL_RenderDrawLines drops pixels on Linux/Unix | ||
|---|---|---|---|
| Product: | SDL | Reporter: | Andreas Schiffler <aschiffler> |
| Component: | render | Assignee: | Ryan C. Gordon <icculus> |
| Status: | ASSIGNED --- | QA Contact: | Sam Lantinga <slouken> |
| Severity: | normal | ||
| Priority: | P2 | CC: | cremoncha, florian.dietrich, sezeroz |
| Version: | HG 2.0 | Keywords: | target-2.0.16 |
| Hardware: | x86_64 | ||
| OS: | Linux | ||
| Attachments: |
Reference image
Test output image Scrrenshot of the bug, the last pixel appears shifted |
||
Created attachment 1948 [details]
Reference image
Created attachment 1949 [details]
Test output image
The same here, February 2020.
In Arch Linux with Qt Creator, I followed a tutorial from the LazyFoo site and also encountered this problem.
A pixel appears after drawing a line and that loose pixel is the same color as the last line drawn.
---
OS: Arch Linux x86_64
Kernel: 5.5.5-zen1-1-zen
Resolution: 1280x1024
WM: i3
CPU: Intel Celeron G1610 (2) @ 2.600GHz
GPU: Intel HD Graphics
Memory: 4895MiB
Vendor: Intel Open Source Technology Center (0x8086)
Device: Mesa DRI Intel(R) Ivybridge Desktop (0x152)
Version: 19.3.4
Accelerated: yes
Video memory: 1536MB
Unified memory: yes
Preferred profile: core (0x1)
Max core profile version: 4.2
Max compat profile version: 3.0
Max GLES1 profile version: 1.1
Max GLES[23] profile version: 3.0
gcc versión 9.2.1 20200130 (Arch Linux 9.2.1+20200130-2)
Qt Creator 4.11.1 - Based on Qt 5.14.1 (GCC 9.2.0, 64 bit)
---
Makefile, for the command line:
#OBJS specifies which files to compile as part of the project
OBJS = main.cpp
#CC specifies which compiler we're using
CC = g++
#COMPILER_FLAGS specifies the additional compilation options we're using
# -w suppresses all warnings
COMPILER_FLAGS = -w
#LINKER_FLAGS specifies the libraries we're linking against
LINKER_FLAGS = -lSDL2 -lSDL2_image
#OBJ_NAME specifies the name of our exectuable
OBJ_NAME = executable
#This is the target that compiles our executable
all : $(OBJS)
$(CC) $(OBJS) $(COMPILER_FLAGS) $(LINKER_FLAGS) -o $(OBJ_NAME)
---
Configuration in the .pro file of Qt Creator:
TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt
SOURCES += \
main.cpp
LIBS += `sdl2-config --cflags --libs`
---
Example used:
/*This source code copyrighted by Lazy Foo' Productions (2004-2020)
and may not be redistributed without written permission.*/
//Using SDL, SDL_image, standard IO, math, and strings
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <stdio.h>
#include <string>
#include <cmath>
//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
//Starts up SDL and creates window
bool init();
//Loads media
bool loadMedia();
//Frees media and shuts down SDL
void close();
//Loads individual image as texture
SDL_Texture* loadTexture( std::string path );
//The window we'll be rendering to
SDL_Window* gWindow = NULL;
//The window renderer
SDL_Renderer* gRenderer = NULL;
bool init()
{
//Initialization flag
bool success = true;
//Initialize SDL
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
printf( "SDL could not initialize! SDL Error: %s\n", SDL_GetError() );
success = false;
}
else
{
//Set texture filtering to linear
if( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) )
{
printf( "Warning: Linear texture filtering not enabled!" );
}
//Create window
gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
if( gWindow == NULL )
{
printf( "Window could not be created! SDL Error: %s\n", SDL_GetError() );
success = false;
}
else
{
//Create renderer for window
gRenderer = SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_ACCELERATED );
if( gRenderer == NULL )
{
printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError() );
success = false;
}
else
{
//Initialize renderer color
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
//Initialize PNG loading
int imgFlags = IMG_INIT_PNG;
if( !( IMG_Init( imgFlags ) & imgFlags ) )
{
printf( "SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError() );
success = false;
}
}
}
}
return success;
}
bool loadMedia()
{
//Loading success flag
bool success = true;
//Nothing to load
return success;
}
void close()
{
//Destroy window
SDL_DestroyRenderer( gRenderer );
SDL_DestroyWindow( gWindow );
gWindow = NULL;
gRenderer = NULL;
//Quit SDL subsystems
IMG_Quit();
SDL_Quit();
}
SDL_Texture* loadTexture( std::string path )
{
//The final texture
SDL_Texture* newTexture = NULL;
//Load image at specified path
SDL_Surface* loadedSurface = IMG_Load( path.c_str() );
if( loadedSurface == NULL )
{
printf( "Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError() );
}
else
{
//Create texture from surface pixels
newTexture = SDL_CreateTextureFromSurface( gRenderer, loadedSurface );
if( newTexture == NULL )
{
printf( "Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );
}
//Get rid of old loaded surface
SDL_FreeSurface( loadedSurface );
}
return newTexture;
}
int main( int argc, char* args[] )
{
//Start up SDL and create window
if( !init() )
{
printf( "Failed to initialize!\n" );
}
else
{
//Load media
if( !loadMedia() )
{
printf( "Failed to load media!\n" );
}
else
{
//Main loop flag
bool quit = false;
//Event handler
SDL_Event e;
//While application is running
while( !quit )
{
//Handle events on queue
while( SDL_PollEvent( &e ) != 0 )
{
//User requests quit
if( e.type == SDL_QUIT )
{
quit = true;
}
}
//Clear screen
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( gRenderer );
//Render red filled quad
SDL_Rect fillRect = { SCREEN_WIDTH / 4, SCREEN_HEIGHT / 4, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 };
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0x00, 0x00, 0xFF );
SDL_RenderFillRect( gRenderer, &fillRect );
//Render green outlined quad
SDL_Rect outlineRect = { SCREEN_WIDTH / 6, SCREEN_HEIGHT / 6, SCREEN_WIDTH * 2 / 3, SCREEN_HEIGHT * 2 / 3 };
SDL_SetRenderDrawColor( gRenderer, 0x00, 0xFF, 0x00, 0xFF );
SDL_RenderDrawRect( gRenderer, &outlineRect );
//Draw blue horizontal line
SDL_SetRenderDrawColor( gRenderer, 0x00, 0x00, 0xFF, 0xFF );
SDL_RenderDrawLine( gRenderer, 0, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT / 2 );
//Draw vertical line of yellow dots
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0x00, 0xFF );
for( int i = 0; i < SCREEN_HEIGHT; i += 4 )
{
SDL_RenderDrawPoint( gRenderer, SCREEN_WIDTH / 2, i );
}
//Update screen
SDL_RenderPresent( gRenderer );
}
}
}
//Free resources and close SDL
close();
return 0;
}
---
I sorry, the configuration of the .pro file of Qt Creator is this.
---
TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt
SOURCES += \
main.cpp
LIBS += -lSDL2_image `sdl2-config --cflags --libs`
---
(In reply to Juan from comment #3) > The same here, February 2020. > > In Arch Linux with Qt Creator, I followed a tutorial from the LazyFoo site > and also encountered this problem. > > A pixel appears after drawing a line and that loose pixel is the same color > as the last line drawn. > > --- > > OS: Arch Linux x86_64 > Kernel: 5.5.5-zen1-1-zen > Resolution: 1280x1024 > WM: i3 > CPU: Intel Celeron G1610 (2) @ 2.600GHz > GPU: Intel HD Graphics > Memory: 4895MiB > > Vendor: Intel Open Source Technology Center (0x8086) > Device: Mesa DRI Intel(R) Ivybridge Desktop (0x152) > Version: 19.3.4 > Accelerated: yes > Video memory: 1536MB > Unified memory: yes > Preferred profile: core (0x1) > Max core profile version: 4.2 > Max compat profile version: 3.0 > Max GLES1 profile version: 1.1 > Max GLES[23] profile version: 3.0 > > gcc versión 9.2.1 20200130 (Arch Linux 9.2.1+20200130-2) > > Qt Creator 4.11.1 - Based on Qt 5.14.1 (GCC 9.2.0, 64 bit) > > --- > > Makefile, for the command line: > > #OBJS specifies which files to compile as part of the project > OBJS = main.cpp > > #CC specifies which compiler we're using > CC = g++ > > #COMPILER_FLAGS specifies the additional compilation options we're using > # -w suppresses all warnings > COMPILER_FLAGS = -w > > #LINKER_FLAGS specifies the libraries we're linking against > LINKER_FLAGS = -lSDL2 -lSDL2_image > > #OBJ_NAME specifies the name of our exectuable > OBJ_NAME = executable > > #This is the target that compiles our executable > all : $(OBJS) > $(CC) $(OBJS) $(COMPILER_FLAGS) $(LINKER_FLAGS) -o $(OBJ_NAME) > > --- > > Configuration in the .pro file of Qt Creator: > > TEMPLATE = app > CONFIG += console c++11 > CONFIG -= app_bundle > CONFIG -= qt > > SOURCES += \ > main.cpp > > LIBS += `sdl2-config --cflags --libs` > > --- > > Example used: > > /*This source code copyrighted by Lazy Foo' Productions (2004-2020) > and may not be redistributed without written permission.*/ > > > //Using SDL, SDL_image, standard IO, math, and strings > #include <SDL2/SDL.h> > #include <SDL2/SDL_image.h> > #include <stdio.h> > #include <string> > #include <cmath> > > > //Screen dimension constants > const int SCREEN_WIDTH = 640; > const int SCREEN_HEIGHT = 480; > > > //Starts up SDL and creates window > bool init(); > //Loads media > bool loadMedia(); > //Frees media and shuts down SDL > void close(); > //Loads individual image as texture > SDL_Texture* loadTexture( std::string path ); > > > //The window we'll be rendering to > SDL_Window* gWindow = NULL; > //The window renderer > SDL_Renderer* gRenderer = NULL; > > > bool init() > { > //Initialization flag > bool success = true; > > //Initialize SDL > if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) > { > printf( "SDL could not initialize! SDL Error: %s\n", SDL_GetError() ); > success = false; > } > else > { > //Set texture filtering to linear > if( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) ) > { > printf( "Warning: Linear texture filtering not enabled!" ); > } > > //Create window > gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, > SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN ); > if( gWindow == NULL ) > { > printf( "Window could not be created! SDL Error: %s\n", SDL_GetError() ); > success = false; > } > else > { > //Create renderer for window > gRenderer = SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_ACCELERATED ); > if( gRenderer == NULL ) > { > printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError() > ); > success = false; > } > else > { > //Initialize renderer color > SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF ); > > //Initialize PNG loading > int imgFlags = IMG_INIT_PNG; > if( !( IMG_Init( imgFlags ) & imgFlags ) ) > { > printf( "SDL_image could not initialize! SDL_image Error: %s\n", > IMG_GetError() ); > success = false; > } > } > } > } > > return success; > } > > > bool loadMedia() > { > //Loading success flag > bool success = true; > > //Nothing to load > return success; > } > > > void close() > { > //Destroy window > SDL_DestroyRenderer( gRenderer ); > SDL_DestroyWindow( gWindow ); > gWindow = NULL; > gRenderer = NULL; > > //Quit SDL subsystems > IMG_Quit(); > SDL_Quit(); > } > > > SDL_Texture* loadTexture( std::string path ) > { > //The final texture > SDL_Texture* newTexture = NULL; > > //Load image at specified path > SDL_Surface* loadedSurface = IMG_Load( path.c_str() ); > if( loadedSurface == NULL ) > { > printf( "Unable to load image %s! SDL_image Error: %s\n", path.c_str(), > IMG_GetError() ); > } > else > { > //Create texture from surface pixels > newTexture = SDL_CreateTextureFromSurface( gRenderer, loadedSurface > ); > if( newTexture == NULL ) > { > printf( "Unable to create texture from %s! SDL Error: %s\n", > path.c_str(), SDL_GetError() ); > } > > //Get rid of old loaded surface > SDL_FreeSurface( loadedSurface ); > } > > return newTexture; > } > > > int main( int argc, char* args[] ) > { > //Start up SDL and create window > if( !init() ) > { > printf( "Failed to initialize!\n" ); > } > else > { > //Load media > if( !loadMedia() ) > { > printf( "Failed to load media!\n" ); > } > else > { > //Main loop flag > bool quit = false; > > //Event handler > SDL_Event e; > > //While application is running > while( !quit ) > { > //Handle events on queue > while( SDL_PollEvent( &e ) != 0 ) > { > //User requests quit > if( e.type == SDL_QUIT ) > { > quit = true; > } > } > > //Clear screen > SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF ); > SDL_RenderClear( gRenderer ); > > //Render red filled quad > SDL_Rect fillRect = { SCREEN_WIDTH / 4, SCREEN_HEIGHT / 4, SCREEN_WIDTH > / 2, SCREEN_HEIGHT / 2 }; > SDL_SetRenderDrawColor( gRenderer, 0xFF, 0x00, 0x00, 0xFF ); > SDL_RenderFillRect( gRenderer, &fillRect ); > > //Render green outlined quad > SDL_Rect outlineRect = { SCREEN_WIDTH / 6, SCREEN_HEIGHT / 6, > SCREEN_WIDTH * 2 / 3, SCREEN_HEIGHT * 2 / 3 }; > SDL_SetRenderDrawColor( gRenderer, 0x00, 0xFF, 0x00, 0xFF ); > SDL_RenderDrawRect( gRenderer, &outlineRect ); > > //Draw blue horizontal line > SDL_SetRenderDrawColor( gRenderer, 0x00, 0x00, 0xFF, 0xFF ); > SDL_RenderDrawLine( gRenderer, 0, SCREEN_HEIGHT / 2, SCREEN_WIDTH, > SCREEN_HEIGHT / 2 ); > > //Draw vertical line of yellow dots > SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0x00, 0xFF ); > for( int i = 0; i < SCREEN_HEIGHT; i += 4 ) > { > SDL_RenderDrawPoint( gRenderer, SCREEN_WIDTH / 2, i ); > } > > //Update screen > SDL_RenderPresent( gRenderer ); > } > } > } > > //Free resources and close SDL > close(); > > return 0; > } > > --- Like you I see the last pixel not aligned with the line. Using SDL 2.0.8 on ubuntu 18.04, I will try with the latest sdl and see if it remains the same. Created attachment 4308 [details]
Scrrenshot of the bug, the last pixel appears shifted
(In reply to Florian D from comment #6) > Created attachment 4308 [details] > Scrrenshot of the bug, the last pixel appears shifted I used SDL 2.0.12-1 on Arch Linux. But yes. It is the same behavior. |
GL_RenderDrawLines (and similar functions) has custom code that handles the "open point" case differently depending on platform. This seems to cause issues on newer versions of Linux (in my case: Linux Mint 17.1 on x86 with radeon rendered, see version info below). Detection is easy with the testautomation render suite: ./testautomation --info render --seed 02BZFAAR8A8MQAHA --filter render_testPrimitives ... Current renderer: Renderer opengl: Flags: 0x0000000A (Accelerated | 0x00000008) Texture formats (5): ARGB8888, YV12, IYUV, NV12, NV21 Max Texture Size: 2048x2048 INFO: 11/30/14 20:11:17: ::::: Test Run /w seed '02BZFAAR8A8MQAHA' started INFO: 11/30/14 20:11:17: Filtering: running only test 'render_testPrimitives' in suite 'Render' ... ERROR: 11/30/14 20:11:18: Comparison of pixels with allowable error of 0 failed 1 times. ERROR: 11/30/14 20:11:18: First detected occurrence at position 50,30 with a squared RGB-difference of 33550. ERROR: 11/30/14 20:11:18: Surfaces from failed comparison saved as 'CompareSurfaces0001_TestOutput.bmp' and 'CompareSurfaces0001_Reference.bmp' ... When analyzing the images, the difference is a missing pixel for the last line rendered in the sequence: test/testautomation_render.c ... ret = SDL_RenderDrawLine(renderer, 79, 0, 50, 29 ); SDLTest_AssertCheck(ret == 0, "Validate result from SDL_RenderDrawLine, expected: 0, got: %i", ret); ret = SDL_RenderDrawLine(renderer, 79, 59, 50, 30 ); SDLTest_AssertCheck(ret == 0, "Validate result from SDL_RenderDrawLine, expected: 0, got: %i", ret); /* Make current */ SDL_RenderPresent(renderer); /* See if it's the same. */ referenceSurface = SDLTest_ImagePrimitives(); _compare(referenceSurface, ALLOWABLE_ERROR_OPAQUE ); ... The cause is the following code (with the invalid code on this platform commented out) in src/render/opengl/SDL_render_gl.c: data->glBegin(GL_POINTS); #if defined(__MACOSX__) || defined(__WIN32__) /* Mac OS X and Windows seem to always leave the last point open */ data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y); #else /* Standard code fixes test case */ data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y); /* Linux seems to leave the right-most or bottom-most point open */ /* Original code breaks test case x1 = points[0].x; y1 = points[0].y; x2 = points[count-1].x; y2 = points[count-1].y; if (x1 > x2) { data->glVertex2f(0.5f + x1, 0.5f + y1); } else if (x2 > x1) { data->glVertex2f(0.5f + x2, 0.5f + y2); } if (y1 > y2) { data->glVertex2f(0.5f + x1, 0.5f + y1); } else if (y2 > y1) { data->glVertex2f(0.5f + x2, 0.5f + y2); } */ #endif data->glEnd(); Other rendering platforms were also affected in the same way on this platform. Linux shuttlebox 3.13.0-37-generic #64-Ubuntu SMP Mon Sep 22 21:30:01 UTC 2014 i686 i686 i686 GNU/Linux gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2 OpenGL vendor string: X.Org R300 Project OpenGL renderer string: Gallium 0.4 on ATI RV350 OpenGL version string: 2.1 Mesa 10.1.3 OpenGL shading language version string: 1.20