From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/opengl32/tests/opengl.c | 274 ++++++++++++++++++++++++++++++++++- 1 file changed, 273 insertions(+), 1 deletion(-) diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c index c45294b134f..3162dd176c5 100644 --- a/dlls/opengl32/tests/opengl.c +++ b/dlls/opengl32/tests/opengl.c @@ -1490,11 +1490,113 @@ next: } } +static void delete_object( enum object_type type, GLuint name ) +{ + switch (type) + { + case OBJ_BUFFER: pglDeleteBuffers( 1, &name ); break; + case OBJ_BUFFER_ARB: pglDeleteBuffersARB( 1, &name ); break; + case OBJ_COMMAND_LIST_NV: pglDeleteCommandListsNV( 1, &name ); break; + case OBJ_FENCE_APPLE: pglDeleteFencesAPPLE( 1, &name ); break; + case OBJ_FENCE_NV: pglDeleteFencesNV( 1, &name ); break; + case OBJ_FRAMEBUFFER: pglDeleteFramebuffers( 1, &name ); break; + case OBJ_FRAMEBUFFER_EXT: pglDeleteFramebuffersEXT( 1, &name ); break; + case OBJ_DISPLAY_LIST: glDeleteLists( name, 1 ); break; + case OBJ_MEMORY_OBJECT_EXT: pglDeleteMemoryObjectsEXT( 1, &name ); break; + case OBJ_OBJECT_BUFFER_ATI: pglDeleteObjectBufferATI( name ); break; + case OBJ_PATH_NV: pglDeletePathsNV( name, 1 ); break; + case OBJ_PROGRAM_ARB: pglDeleteProgramsARB( 1, &name ); break; + case OBJ_PROGRAM_NV: pglDeleteProgramsNV( 1, &name ); break; + case OBJ_SHADER_EXT: pglDeleteVertexShaderEXT( name ); break; + case OBJ_SHADER_ATI: pglDeleteFragmentShaderATI( name ); break; + case OBJ_PROGRAM_OBJECT: pglDeleteProgram( name ); break; + case OBJ_PROGRAM_OBJECT_ARB: pglDeleteObjectARB( name ); break; + case OBJ_SHADER_OBJECT: pglDeleteShader( name ); break; + case OBJ_SHADER_OBJECT_ARB: pglDeleteObjectARB( name ); break; + case OBJ_PROGRAM_PIPELINE: pglDeleteProgramPipelines( 1, &name ); break; + case OBJ_QUERY: pglDeleteQueries( 1, &name ); break; + case OBJ_QUERY_ARB: pglDeleteQueriesARB( 1, &name ); break; + case OBJ_OCCLUSION_QUERY_NV: pglDeleteOcclusionQueriesNV( 1, &name ); break; + case OBJ_RENDERBUFFER: pglDeleteRenderbuffers( 1, &name ); break; + case OBJ_RENDERBUFFER_EXT: pglDeleteRenderbuffersEXT( 1, &name ); break; + case OBJ_SAMPLER: pglDeleteSamplers( 1, &name ); break; + case OBJ_SEMAPHORE_EXT: pglDeleteSemaphoresEXT( 1, &name ); break; + case OBJ_STATE_NV: pglDeleteStatesNV( 1, &name ); break; + case OBJ_TEXTURE: glDeleteTextures( 1, &name ); break; + case OBJ_TEXTURE_EXT: pglDeleteTexturesEXT( 1, &name ); break; + case OBJ_TRANSFORM_FEEDBACK: pglDeleteTransformFeedbacks( 1, &name ); break; + case OBJ_TRANSFORM_FEEDBACK_NV: pglDeleteTransformFeedbacksNV( 1, &name ); break; + case OBJ_VERTEX_ARRAY: pglDeleteVertexArrays( 1, &name ); break; + case OBJ_VERTEX_ARRAY_APPLE: pglDeleteVertexArraysAPPLE( 1, &name ); break; + case OBJ_TYPE_COUNT: return; + } +} + +static GLboolean GLAPIENTRY is_program_object_arb( GLuint name ) +{ + GLint type = 0xdeadbeef; + pglGetObjectParameterivARB( name, GL_OBJECT_TYPE_ARB, &type ); + if (type != GL_PROGRAM_OBJECT_ARB) glGetError(); /* other glIs* functions don't set error on failure */ + return type == GL_PROGRAM_OBJECT_ARB; +} + +static GLboolean GLAPIENTRY is_shader_object_arb( GLuint name ) +{ + GLint type = 0xdeadbeef; + pglGetObjectParameterivARB( name, GL_OBJECT_TYPE_ARB, &type ); + if (type != GL_SHADER_OBJECT_ARB) glGetError(); /* other glIs* functions don't set error on failure */ + return type == GL_SHADER_OBJECT_ARB; +} + static void test_sharelists(HDC winhdc) { + const struct object_test + { + enum object_type type; + GLboolean (*GLAPIENTRY exists)( GLuint name ); + BOOL shared; + BOOL supported; + } object_tests[] = + { + { OBJ_BUFFER, pglIsBuffer, TRUE, !!pglIsBuffer }, + { OBJ_BUFFER_ARB, pglIsBufferARB, TRUE, !!pglIsBufferARB }, + { OBJ_FRAMEBUFFER, pglIsFramebuffer, TRUE, !!pglIsFramebuffer }, + { OBJ_FRAMEBUFFER_EXT, pglIsFramebufferEXT, TRUE, !!pglIsFramebufferEXT }, + { OBJ_RENDERBUFFER, pglIsRenderbuffer, TRUE, !!pglIsRenderbuffer }, + { OBJ_RENDERBUFFER_EXT, pglIsRenderbufferEXT, TRUE, !!pglIsRenderbufferEXT }, + { OBJ_TEXTURE, glIsTexture, TRUE, TRUE }, + { OBJ_TEXTURE_EXT, pglIsTextureEXT, TRUE, !!pglIsTextureEXT }, + { OBJ_SAMPLER, pglIsSampler, TRUE, !!pglIsSampler }, + { OBJ_DISPLAY_LIST, glIsList, TRUE, TRUE }, + { OBJ_PROGRAM_ARB, pglIsProgramARB, TRUE, !!pglIsProgramARB }, + { OBJ_PROGRAM_NV, pglIsProgramNV, TRUE, !!pglIsProgramNV }, + { OBJ_SEMAPHORE_EXT, pglIsSemaphoreEXT, TRUE, !!pglIsSemaphoreEXT }, + { OBJ_MEMORY_OBJECT_EXT, pglIsMemoryObjectEXT, TRUE, !!pglIsMemoryObjectEXT }, + { OBJ_PATH_NV, pglIsPathNV, TRUE, !!pglIsPathNV }, + { OBJ_PROGRAM_OBJECT, pglIsProgram, TRUE, !!pglIsProgram }, + { OBJ_PROGRAM_OBJECT_ARB, is_program_object_arb, TRUE, !!pglCreateProgramObjectARB }, + { OBJ_SHADER_OBJECT, pglIsShader, TRUE, !!pglIsShader }, + { OBJ_SHADER_OBJECT_ARB, is_shader_object_arb, TRUE, !!pglCreateShaderObjectARB }, + { OBJ_SHADER_EXT, NULL, TRUE, !!pglGenVertexShadersEXT }, + { OBJ_SHADER_ATI, NULL, TRUE, !!pglGenFragmentShadersATI }, + /* non shared objects */ + { OBJ_OBJECT_BUFFER_ATI, pglIsObjectBufferATI, FALSE /* needs confirmation */, !!pglIsObjectBufferATI }, + { OBJ_COMMAND_LIST_NV, pglIsCommandListNV, FALSE, !!pglIsCommandListNV }, + { OBJ_FENCE_APPLE, pglIsFenceAPPLE, FALSE, !!pglIsFenceAPPLE }, + { OBJ_FENCE_NV, pglIsFenceNV, FALSE, !!pglIsFenceNV }, + { OBJ_PROGRAM_PIPELINE, pglIsProgramPipeline, FALSE, !!pglIsProgramPipeline }, + { OBJ_QUERY, pglIsQuery, FALSE, !!pglIsQuery }, + { OBJ_QUERY_ARB, pglIsQueryARB, FALSE, !!pglIsQueryARB }, + { OBJ_OCCLUSION_QUERY_NV, pglIsOcclusionQueryNV, FALSE, !!pglIsOcclusionQueryNV }, + { OBJ_STATE_NV, pglIsStateNV, FALSE, !!pglIsStateNV }, + { OBJ_TRANSFORM_FEEDBACK, pglIsTransformFeedback, FALSE, !!pglIsTransformFeedback }, + { OBJ_TRANSFORM_FEEDBACK_NV, pglIsTransformFeedbackNV, FALSE, !!pglIsTransformFeedbackNV }, + { OBJ_VERTEX_ARRAY, pglIsVertexArray, FALSE, !!pglIsVertexArray }, + { OBJ_VERTEX_ARRAY_APPLE, pglIsVertexArrayAPPLE, FALSE, !!pglIsVertexArrayAPPLE }, + }; BOOL res, nvidia, amd, source_current, source_sharing, dest_current, dest_sharing; const char *extensions = (const char*)glGetString(GL_EXTENSIONS); - HGLRC source, dest, other; + HGLRC source, dest, other, ctx1, ctx2, ctx3; BOOL ms_hint_supported; ms_hint_supported = gl_extension_supported(extensions, "GL_NV_multisample_filter_hint"); @@ -1734,6 +1836,176 @@ static void test_sharelists(HDC winhdc) } } } + + for (UINT i = 0; i < ARRAY_SIZE(object_tests); i++) + { + /* some functions don't allow implicit names even in compat contexts */ + const struct object_test *test = object_tests + i; + GLuint obj1, obj2, obj3; + + if (!test->exists) + { + skip( "Skipping object type %s\n", debugstr_object_type( test->type ) ); + continue; + } + + winetest_push_context( "%u %s", i, debugstr_object_type( test->type ) ); + + ctx1 = wglCreateContext( winhdc ); + ok_ptr( ctx1, !=, NULL ); + ctx2 = wglCreateContext( winhdc ); + ok_ptr( ctx2, !=, NULL ); + ctx3 = wglCreateContext( winhdc ); + ok_ptr( ctx3, !=, NULL ); + + ok_ret( TRUE, wglMakeCurrent( winhdc, ctx1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + + /* create object 1 in ctx1 (lists #1) */ + ok_ret( FALSE, test->exists( 1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + create_object( test->type, is_implicit_allowed( test->type, TRUE ) ? 1 : 0, &obj1 ); + ok_ret( GL_NO_ERROR, glGetError() ); + ok_u4( obj1, ==, 1 ); + ok_ret( TRUE, test->exists( obj1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + + /* share ctx1 (lists #1) with ctx2 */ + ok_ret( TRUE, wglShareLists( ctx1, ctx2 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + /* object 1 is still valid in ctx1 */ + ok_ret( TRUE, test->exists( obj1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + + /* object 1 is now valid in ctx2 */ + ok_ret( TRUE, wglMakeCurrent( winhdc, ctx2 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + if (!test->shared) + { + ok_ret( FALSE, test->exists( obj1 ) ); + ok_ret( TRUE, wglDeleteContext( ctx1 ) ); + ok_ret( TRUE, wglDeleteContext( ctx2 ) ); + ok_ret( TRUE, wglDeleteContext( ctx3 ) ); + winetest_pop_context(); + continue; + } + ok_ret( TRUE, test->exists( obj1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + + /* object 1 is not valid in ctx3 */ + ok_ret( TRUE, wglMakeCurrent( winhdc, ctx3 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( FALSE, test->exists( obj1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + /* share ctx1 (lists #1) with ctx3 */ + ok_ret( TRUE, wglShareLists( ctx1, ctx3 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + /* object 1 is now valid there as well */ + todo_wine ok_ret( TRUE, test->exists( obj1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + + /* object 1 is still valid in ctx2 */ + ok_ret( TRUE, wglMakeCurrent( winhdc, ctx2 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( TRUE, test->exists( obj1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + + ok_ret( TRUE, wglDeleteContext( ctx1 ) ); + + /* now try the other way around */ + ctx1 = wglCreateContext( winhdc ); + ok_ptr( ctx1, !=, NULL ); + ok_ret( TRUE, wglMakeCurrent( winhdc, ctx1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + + /* create object 2 in ctx1 (lists #2) */ + ok_ret( FALSE, test->exists( 2 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + create_object( test->type, is_implicit_allowed( test->type, TRUE ) ? 2 : 0, &obj2 ); + ok_ret( GL_NO_ERROR, glGetError() ); + if (obj2 != 2) + { + GLuint tmp = obj2; + create_object( test->type, is_implicit_allowed( test->type, TRUE ) ? 2 : 0, &obj2 ); + delete_object( test->type, tmp ); + } + ok_u4( obj2, ==, 2 ); + ok_ret( TRUE, test->exists( obj2 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + /* object 1 in invalid in ctx1 */ + ok_ret( FALSE, test->exists( obj1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + + /* cannot overwrite non-empty lists with some other */ + todo_wine ok_ret( FALSE, wglShareLists( ctx1, ctx3 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( FALSE, wglShareLists( ctx2, ctx1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + + /* even after deleting all the objects */ + delete_object( test->type, obj2 ); + ok_ret( FALSE, test->exists( obj2 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( FALSE, wglShareLists( ctx2, ctx1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + + + ok_ret( TRUE, wglMakeCurrent( winhdc, ctx2 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( TRUE, test->exists( obj1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( FALSE, test->exists( obj2 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( FALSE, test->exists( 3 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + + /* test creating objects in shared contexts */ + create_object( test->type, is_implicit_allowed( test->type, TRUE ) ? 3 : 0, &obj3 ); + ok_ret( GL_NO_ERROR, glGetError() ); + if (obj3 != 3) + { + GLuint tmp = obj3; + create_object( test->type, is_implicit_allowed( test->type, TRUE ) ? 3 : 0, &obj3 ); + delete_object( test->type, tmp ); + } + ok_u4( obj3, ==, 3 ); + ok_ret( TRUE, wglMakeCurrent( winhdc, ctx3 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + todo_wine ok_ret( TRUE, test->exists( obj1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( FALSE, test->exists( obj2 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + todo_wine ok_ret( TRUE, test->exists( obj3 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + + /* test deleting objects in shared contexts */ + delete_object( test->type, obj1 ); + todo_wine_if( test->type == OBJ_PROGRAM_OBJECT || test->type == OBJ_PROGRAM_OBJECT_ARB || + test->type == OBJ_SHADER_OBJECT || test->type == OBJ_SHADER_OBJECT_ARB ) + ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( TRUE, wglMakeCurrent( winhdc, ctx2 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + todo_wine ok_ret( FALSE, test->exists( obj1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( FALSE, test->exists( obj2 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( TRUE, test->exists( obj3 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + + ok_ret( TRUE, wglDeleteContext( ctx1 ) ); + ok_ret( TRUE, wglDeleteContext( ctx3 ) ); + + /* objects are still valid after shared context destruction */ + todo_wine ok_ret( FALSE, test->exists( obj1 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( FALSE, test->exists( obj2 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( TRUE, test->exists( obj3 ) ); + ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( TRUE, wglDeleteContext( ctx2 ) ); + + winetest_pop_context(); + } } static void test_makecurrent(HDC winhdc) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10739