diff options
Diffstat (limited to 'mesalib')
56 files changed, 2496 insertions, 386 deletions
diff --git a/mesalib/configure.ac b/mesalib/configure.ac index a8366ee2f..8fb5e0d8b 100644 --- a/mesalib/configure.ac +++ b/mesalib/configure.ac @@ -34,9 +34,10 @@ LIBDRM_NVVIEUX_REQUIRED=2.4.33 LIBDRM_NOUVEAU_REQUIRED="2.4.33 libdrm >= 2.4.41" LIBDRM_FREEDRENO_REQUIRED=2.4.39 DRI2PROTO_REQUIRED=2.6 +DRI3PROTO_REQUIRED=1.0 +PRESENTPROTO_REQUIRED=1.0 +LIBUDEV_REQUIRED=151 GLPROTO_REQUIRED=1.4.14 -LIBDRM_XORG_REQUIRED=2.4.24 -LIBKMS_XORG_REQUIRED=1.0.0 dnl Check for progs AC_PROG_CPP @@ -556,11 +557,6 @@ AC_ARG_ENABLE([egl], [enable_egl="$enableval"], [enable_egl=yes]) -AC_ARG_ENABLE([xorg], - [AS_HELP_STRING([--enable-xorg], - [enable support for X.Org DDX API @<:@default=no@:>@])], - [enable_xorg="$enableval"], - [enable_xorg=no]) AC_ARG_ENABLE([xa], [AS_HELP_STRING([--enable-xa], [enable build of the XA X Acceleration API @<:@default=no@:>@])], @@ -651,7 +647,6 @@ if test "x$enable_opengl" = xno -a \ "x$enable_gles1" = xno -a \ "x$enable_gles2" = xno -a \ "x$enable_openvg" = xno -a \ - "x$enable_xorg" = xno -a \ "x$enable_xa" = xno -a \ "x$enable_xvmc" = xno -a \ "x$enable_vdpau" = xno -a \ @@ -816,10 +811,13 @@ xyesno) fi PKG_CHECK_MODULES([DRI2PROTO], [dri2proto >= $DRI2PROTO_REQUIRED]) GL_PC_REQ_PRIV="$GL_PC_REQ_PRIV libdrm >= $LIBDRM_REQUIRED" + PKG_CHECK_MODULES([DRI3PROTO], [dri3proto >= $DRI3PROTO_REQUIRED]) + PKG_CHECK_MODULES([PRESENTPROTO], [presentproto >= $PRESENTPROTO_REQUIRED]) + PKG_CHECK_MODULES([LIBUDEV], [libudev >= $LIBUDEV_REQUIRED]) fi # find the DRI deps for libGL - dri_modules="x11 xext xdamage xfixes x11-xcb xcb-glx >= 1.8.1 xcb-dri2 >= 1.8" + dri_modules="x11 xext xdamage xfixes x11-xcb xcb-glx >= 1.8.1 xcb-dri2 >= 1.8 xcb-dri3 xcb-present xcb-sync xshmfence" # add xf86vidmode if available PKG_CHECK_MODULES([XF86VIDMODE], [xxf86vm], HAVE_XF86VIDMODE=yes, HAVE_XF86VIDMODE=no) @@ -829,8 +827,8 @@ xyesno) PKG_CHECK_MODULES([DRIGL], [$dri_modules]) GL_PC_REQ_PRIV="$GL_PC_REQ_PRIV $dri_modules" - X11_INCLUDES="$X11_INCLUDES $DRIGL_CFLAGS" - GL_LIB_DEPS="$DRIGL_LIBS" + X11_INCLUDES="$X11_INCLUDES $DRIGL_CFLAGS $LIBUDEV_CFLAGS" + GL_LIB_DEPS="$DRIGL_LIBS $LIBUDEV_LIBS" # need DRM libs, $PTHREAD_LIBS, etc. GL_LIB_DEPS="$GL_LIB_DEPS $LIBDRM_LIBS -lm $PTHREAD_LIBS $DLOPEN_LIBS" @@ -1236,20 +1234,6 @@ fi AM_CONDITIONAL(HAVE_GALLIUM_GBM, test "x$enable_gallium_gbm" = xyes) dnl -dnl X.Org DDX configuration -dnl -if test "x$enable_xorg" = xyes; then - PKG_CHECK_MODULES([XORG], [xorg-server >= 1.6.0]) - PKG_CHECK_MODULES([LIBDRM_XORG], [libdrm >= $LIBDRM_XORG_REQUIRED]) - PKG_CHECK_MODULES([LIBKMS_XORG], [libkms >= $LIBKMS_XORG_REQUIRED]) - PKG_CHECK_MODULES(XEXT, [xextproto >= 7.0.99.1], - HAVE_XEXTPROTO_71="yes"; DEFINES="$DEFINES -DHAVE_XEXTPROTO_71", - HAVE_XEXTPROTO_71="no") - GALLIUM_STATE_TRACKERS_DIRS="xorg $GALLIUM_STATE_TRACKERS_DIRS" -fi -AM_CONDITIONAL(HAVE_ST_XORG, test "x$enable_xorg" = xyes) - -dnl dnl XA configuration dnl if test "x$enable_xa" = xyes; then @@ -1487,13 +1471,6 @@ AC_ARG_WITH([egl-driver-dir], [EGL_DRIVER_INSTALL_DIR='${libdir}/egl']) AC_SUBST([EGL_DRIVER_INSTALL_DIR]) -AC_ARG_WITH([xorg-driver-dir], - [AS_HELP_STRING([--with-xorg-driver-dir=DIR], - [Default xorg driver directory[[default=${libdir}/xorg/modules/drivers]]])], - [XORG_DRIVER_INSTALL_DIR="$withval"], - [XORG_DRIVER_INSTALL_DIR="${libdir}/xorg/modules/drivers"]) -AC_SUBST([XORG_DRIVER_INSTALL_DIR]) - AC_ARG_WITH([max-width], [AS_HELP_STRING([--with-max-width=N], [Maximum framebuffer width (4096)])], @@ -1675,18 +1652,15 @@ gallium_check_st() { if test "x$enable_dri" = xyes && test "x$2" != x; then GALLIUM_TARGET_DIRS="$GALLIUM_TARGET_DIRS $2" fi - if test "x$enable_xorg" = xyes && test "x$3" != x; then + if test "x$enable_xa" = xyes && test "x$3" != x; then GALLIUM_TARGET_DIRS="$GALLIUM_TARGET_DIRS $3" fi - if test "x$enable_xa" = xyes && test "x$4" != x; then + if test "x$enable_xvmc" = xyes && test "x$4" != x; then GALLIUM_TARGET_DIRS="$GALLIUM_TARGET_DIRS $4" fi - if test "x$enable_xvmc" = xyes && test "x$5" != x; then + if test "x$enable_vdpau" = xyes && test "x$5" != x; then GALLIUM_TARGET_DIRS="$GALLIUM_TARGET_DIRS $5" fi - if test "x$enable_vdpau" = xyes && test "x$6" != x; then - GALLIUM_TARGET_DIRS="$GALLIUM_TARGET_DIRS $6" - fi } gallium_require_llvm() { @@ -1726,9 +1700,8 @@ radeon_llvm_check() { } dnl Gallium drivers -if test "x$enable_dri" = xyes -o "x$enable_xorg" = xyes -o \ - "x$enable_xa" = xyes -o "x$enable_xvmc" = xyes -o \ - "x$enable_vdpau" = xyes; then +if test "x$enable_dri" = xyes -o "x$enable_xa" = xyes -o \ + "x$enable_xvmc" = xyes -o "x$enable_vdpau" = xyes; then NEED_NONNULL_WINSYS=yes fi AM_CONDITIONAL(NEED_NONNULL_WINSYS, test "x$NEED_NONNULL_WINSYS" = xyes) @@ -1741,7 +1714,7 @@ if test "x$with_gallium_drivers" != x; then xsvga) HAVE_GALLIUM_SVGA=yes GALLIUM_DRIVERS_DIRS="$GALLIUM_DRIVERS_DIRS svga softpipe" - gallium_check_st "svga/drm" "dri-vmwgfx" "" "xa-vmwgfx" + gallium_check_st "svga/drm" "dri-vmwgfx" "xa-vmwgfx" ;; xi915) HAVE_GALLIUM_I915=yes @@ -1751,7 +1724,7 @@ if test "x$with_gallium_drivers" != x; then GALLIUM_DRIVERS_DIRS="$GALLIUM_DRIVERS_DIRS llvmpipe" fi GALLIUM_WINSYS_DIRS="$GALLIUM_WINSYS_DIRS i915/sw" - gallium_check_st "i915/drm" "dri-i915" "xorg-i915" + gallium_check_st "i915/drm" "dri-i915" DRICOMMON_NEED_LIBDRM=yes ;; xilo) @@ -1767,7 +1740,7 @@ if test "x$with_gallium_drivers" != x; then PKG_CHECK_MODULES([RADEON], [libdrm_radeon >= $LIBDRM_RADEON_REQUIRED]) gallium_require_llvm "Gallium R300" GALLIUM_DRIVERS_DIRS="$GALLIUM_DRIVERS_DIRS r300" - gallium_check_st "radeon/drm" "r300/dri" "" "" "" "" + gallium_check_st "radeon/drm" "r300/dri" "" "" "" DRICOMMON_NEED_LIBDRM=yes ;; xr600) @@ -1785,7 +1758,7 @@ if test "x$with_gallium_drivers" != x; then if test "x$enable_opencl" = xyes; then LLVM_COMPONENTS="${LLVM_COMPONENTS} bitreader asmparser" fi - gallium_check_st "radeon/drm" "r600/dri" "" "" "r600/xvmc" "r600/vdpau" + gallium_check_st "radeon/drm" "r600/dri" "" "r600/xvmc" "r600/vdpau" DRICOMMON_NEED_LIBDRM=yes ;; xradeonsi) @@ -1794,7 +1767,7 @@ if test "x$with_gallium_drivers" != x; then gallium_require_drm_loader GALLIUM_DRIVERS_DIRS="$GALLIUM_DRIVERS_DIRS radeonsi" radeon_llvm_check - gallium_check_st "radeon/drm" "radeonsi/dri" "" "" "" "radeonsi/vdpau" "" + gallium_check_st "radeon/drm" "radeonsi/dri" "" "" "radeonsi/vdpau" DRICOMMON_NEED_LIBDRM=yes ;; xnouveau) @@ -1802,7 +1775,7 @@ if test "x$with_gallium_drivers" != x; then PKG_CHECK_MODULES([NOUVEAU], [libdrm_nouveau >= $LIBDRM_NOUVEAU_REQUIRED]) gallium_require_drm_loader GALLIUM_DRIVERS_DIRS="$GALLIUM_DRIVERS_DIRS nouveau" - gallium_check_st "nouveau/drm" "dri-nouveau" "xorg-nouveau" "" "xvmc-nouveau" "vdpau-nouveau" + gallium_check_st "nouveau/drm" "dri-nouveau" "" "xvmc-nouveau" "vdpau-nouveau" DRICOMMON_NEED_LIBDRM=yes ;; xfreedreno) @@ -1810,7 +1783,7 @@ if test "x$with_gallium_drivers" != x; then PKG_CHECK_MODULES([FREEDRENO], [libdrm_freedreno >= $LIBDRM_FREEDRENO_REQUIRED]) gallium_require_drm_loader GALLIUM_DRIVERS_DIRS="$GALLIUM_DRIVERS_DIRS freedreno" - gallium_check_st "freedreno/drm" "dri-freedreno" "" "" "" "" + gallium_check_st "freedreno/drm" "dri-freedreno" "" "" "" DRICOMMON_NEED_LIBDRM=yes ;; xswrast) @@ -1938,9 +1911,9 @@ AM_CONDITIONAL(HAVE_X11_DRIVER, test "x$enable_xlib_glx" = xyes) AM_CONDITIONAL(HAVE_OSMESA, test "x$enable_osmesa" = xyes) AM_CONDITIONAL(HAVE_GALLIUM_OSMESA, test "x$enable_gallium_osmesa" = xyes) -AM_CONDITIONAL(HAVE_X86_ASM, echo "$DEFINES" | grep 'X86_ASM' >/dev/null 2>&1) -AM_CONDITIONAL(HAVE_X86_64_ASM, echo "$DEFINES" | grep 'X86_64_ASM' >/dev/null 2>&1) -AM_CONDITIONAL(HAVE_SPARC_ASM, echo "$DEFINES" | grep 'SPARC_ASM' >/dev/null 2>&1) +AM_CONDITIONAL(HAVE_X86_ASM, test "x$asm_arch" = xx86 -o "x$asm_arch" = xx86_64) +AM_CONDITIONAL(HAVE_X86_64_ASM, test "x$asm_arch" = xx86_64) +AM_CONDITIONAL(HAVE_SPARC_ASM, test "x$asm_arch" = xsparc) AC_SUBST([VDPAU_MAJOR], 1) AC_SUBST([VDPAU_MINOR], 0) @@ -2013,7 +1986,6 @@ AC_CONFIG_FILES([Makefile src/gallium/state_trackers/vdpau/Makefile src/gallium/state_trackers/vega/Makefile src/gallium/state_trackers/xa/Makefile - src/gallium/state_trackers/xorg/Makefile src/gallium/state_trackers/xvmc/Makefile src/gallium/targets/Makefile src/gallium/targets/dri-freedreno/Makefile @@ -2038,8 +2010,6 @@ AC_CONFIG_FILES([Makefile src/gallium/targets/vdpau-nouveau/Makefile src/gallium/targets/xa-vmwgfx/Makefile src/gallium/targets/xa-vmwgfx/xatracker.pc - src/gallium/targets/xorg-i915/Makefile - src/gallium/targets/xorg-nouveau/Makefile src/gallium/targets/xvmc-nouveau/Makefile src/gallium/tests/trivial/Makefile src/gallium/tests/unit/Makefile @@ -2091,9 +2061,7 @@ AC_CONFIG_FILES([Makefile src/mesa/drivers/osmesa/osmesa.pc src/mesa/drivers/x11/Makefile src/mesa/main/tests/Makefile - src/mesa/main/tests/hash_table/Makefile - src/mesa/x86-64/Makefile - src/mesa/x86/Makefile]) + src/mesa/main/tests/hash_table/Makefile]) dnl Sort the dirs alphabetically GALLIUM_TARGET_DIRS=`echo $GALLIUM_TARGET_DIRS|tr " " "\n"|sort -u|tr "\n" " "` diff --git a/mesalib/docs/GL3.txt b/mesalib/docs/GL3.txt index 7d100dff1..a8cffab44 100644 --- a/mesalib/docs/GL3.txt +++ b/mesalib/docs/GL3.txt @@ -106,8 +106,8 @@ GL_ARB_tessellation_shader not started GL_ARB_texture_buffer_object_rgb32 DONE (i965, r600, radeonsi, softpipe) GL_ARB_texture_cube_map_array DONE (i965, r600, softpipe) GL_ARB_texture_gather DONE (i965) -GL_ARB_transform_feedback2 DONE (r600, radeonsi) -GL_ARB_transform_feedback3 DONE (r600, radeonsi) +GL_ARB_transform_feedback2 DONE (i965, r600, radeonsi) +GL_ARB_transform_feedback3 DONE (i965, r600, radeonsi) GL 4.1: @@ -126,9 +126,9 @@ GL 4.2: GLSL 4.2 not started GL_ARB_texture_compression_bptc not started GL_ARB_compressed_texture_pixel_storage not started -GL_ARB_shader_atomic_counters in progress (Curro) +GL_ARB_shader_atomic_counters DONE (i965) GL_ARB_texture_storage DONE (all drivers) -GL_ARB_transform_feedback_instanced DONE (r600, radeonsi) +GL_ARB_transform_feedback_instanced DONE (i965, r600, radeonsi) GL_ARB_base_instance DONE (i965, nv50, nvc0, r600, radeonsi) GL_ARB_shader_image_load_store not started GL_ARB_conservative_depth DONE (all drivers that support GLSL 1.30) @@ -161,7 +161,7 @@ GL_ARB_texture_buffer_range DONE (nv50, nvc0, i965, r60 GL_ARB_texture_query_levels DONE (i965) GL_ARB_texture_storage_multisample DONE (all drivers that support GL_ARB_texture_multisample) GL_ARB_texture_view not started -GL_ARB_vertex_attrib_binding started (Fredrik) +GL_ARB_vertex_attrib_binding DONE (all drivers) GL 4.4: @@ -175,7 +175,7 @@ GL_ARB_multi_bind not started GL_ARB_query_buffer_object not started GL_ARB_texture_mirror_clamp_to_edge DONE (i965, nv30, nv50, nvc0, r300, r600, radeonsi, swrast) GL_ARB_texture_stencil8 not started -GL_ARB_vertex_type_10f_11f_11f_rev not started +GL_ARB_vertex_type_10f_11f_11f_rev DONE (i965, r600) More info about these features and the work involved can be found at diff --git a/mesalib/docs/relnotes/10.0.html b/mesalib/docs/relnotes/10.0.html index b74d03dc2..eabe77f83 100644 --- a/mesalib/docs/relnotes/10.0.html +++ b/mesalib/docs/relnotes/10.0.html @@ -51,6 +51,9 @@ Note: some of the new features are only available with certain drivers. <li>GL_ARB_texture_mirror_clamp_to_edge.</li> <li>GL_ARB_transform_feedback2, GL_ARB_transform_feedback3, and GL_ARB_transform_feedback_instanced on i965/Gen7 (with appropriate kernel support).</li> <li>GL_ARB_sample_shading on i965.</li> +<li>GL_ARB_shader_atomic_counters on i965.</li> +<li>GL_ARB_vertex_attrib_binding</li> +<li>GL_ARB_vertex_type_10f_11f_11f_rev on i965 and r600g</li> <li>GL_KHR_debug</li> </ul> diff --git a/mesalib/docs/specs/MESA_query_renderer.spec b/mesalib/docs/specs/MESA_query_renderer.spec new file mode 100644 index 000000000..bf0975669 --- /dev/null +++ b/mesalib/docs/specs/MESA_query_renderer.spec @@ -0,0 +1,405 @@ +Name + + MESA_query_renderer + +Name Strings + + GLX_MESA_query_renderer + +Contact + + Ian Romanick <ian.d.romanick@intel.com> + +IP Status + + No known IP claims. + +Status + + Incomplete. DO NOT SHIP. + +Version + + Version 6, 7-November-2013 + +Number + + TBD. + +Dependencies + + GLX 1.4 is required. + + GLX_ARB_create_context and GLX_ARB_create_context_profile are required. + + This extension interacts with GLX_EXT_create_context_es2_profile and + GLX_EXT_create_context_es_profile. + +Overview + + In many situations, applications want to detect characteristics of a + rendering device before creating a context for that device. Information + gathered at this stage may guide choices the application makes about + color depth, number of samples per-pixel, texture quality, and so on. + In addition, versions of supported APIs and implementation API + preference may also guide start-up decisions made by the application. + For example, one implementation may prefer vertex data be supplied using + methods only available in a compatibility profile, but another + implementation may only support the desired version in a core profile. + + There are also cases where more than one renderer may be available per + display. For example, there is typically a hardware implementation and + a software based implementation. There are cases where an application + may want to pick one over the other. One such situation is when the + software implementation supports more features than the hardware + implementation. Another situation is when a particular version of the + hardware implementation is blacklisted due to known bugs. + + This extension provides a mechanism for the application to query all of + the available renderers for a particular display and screen. In + addition, this extension provides a mechanism for applications to create + contexts with respect to a specific renderer. + +New Procedures and Functions + + Bool glXQueryRendererIntegerMESA(Display *dpy, int screen, + int renderer, int attribute, + unsigned int *value); + Bool glXQueryCurrentRendererIntegerMESA(int attribute, unsigned int *value); + + const char *glXQueryRendererStringMESA(Display *dpy, int screen, + int renderer, int attribute); + + const char *glXQueryCurrentRendererStringMESA(int attribute); + +New Tokens + + Accepted as an <attribute> in glXQueryRendererIntegerMESA and + glXQueryCurrentRendererIntegerMESA: + + GLX_RENDERER_VENDOR_ID_MESA 0x8183 + GLX_RENDERER_DEVICE_ID_MESA 0x8184 + GLX_RENDERER_VERSION_MESA 0x8185 + GLX_RENDERER_ACCELERATED_MESA 0x8186 + GLX_RENDERER_VIDEO_MEMORY_MESA 0x8187 + GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA 0x8188 + GLX_RENDERER_PREFERRED_PROFILE_MESA 0x8189 + GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA 0x818A + GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA 0x818B + GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA 0x818C + GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA 0x818D + + Accepted as an <attribute> in glXQueryRendererStringMESA and + glXQueryCurrentRendererStringMESA: + + GLX_RENDERER_VENDOR_ID_MESA + GLX_RENDERER_DEVICE_ID_MESA + + Accepted as an attribute name in <*attrib_list> in + glXCreateContextAttribsARB: + + GLX_RENDERER_ID_MESA 0x818E + +Additions to the OpenGL / WGL Specifications + + None. This specification is written for GLX. + +Additions to the GLX 1.4 Specification + + [Add the following to Section X.Y.Z of the GLX Specification] + + To obtain information about the available renderers for a particular + display and screen, + + Bool glXQueryRendererIntegerMESA(Display *dpy, int screen, int renderer, + int attribute, unsigned int *value); + + can be used. The value for <attribute> will be returned in one or more + integers specified by <value>. The values, data sizes, and descriptions + of each renderer attribute are listed in the table below. + + GLX renderer attribute number description + of values + ---------------------- --------- ----------- + GLX_RENDERER_VENDOR_ID_MESA 1 PCI ID of the device vendor + GLX_RENDERER_DEVICE_ID_MESA 1 PCI ID of the device + GLX_RENDERER_VERSION_MESA 3 Major, minor, and patch level of + the renderer implementation + GLX_RENDERER_ACCELERATED_MESA 1 Boolean indicating whether or + not the renderer is hardware + accelerated + GLX_RENDERER_VIDEO_MEMORY_MESA 1 Number of megabytes of video + memory available to the renderer + GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA + 1 Boolean indicating whether or + not the renderer uses a unified + memory architecture or has + separate "on-card" and GART + memory. + GLX_RENDERER_PREFERRED_PROFILE_MESA + 1 Bitmask of the preferred context + profile for this renderer. This + value is suitable to be supplied + with the + GLX_CONTEXT_PROFILE_MASK_ARB + attribute to + glXCreateContextAttribsARB + GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA + 2 Maximum core profile major and + minor version supported by the + renderer + GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA + 2 Maximum compatibility profile + major and minor version + supported by the renderer + GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA + 2 Maximum OpenGL ES 1.x + major and minor version + supported by the renderer + GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA + 2 Maximum OpenGL ES 2.x or 3.x + major and minor version + supported by the renderer + + In the table, boolean attributes will have either the value 0 or 1. + + GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA, + GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA, + GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA, and + GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA each return <0, 0> in + *value if no version of that profile is supported. + + GLX_RENDERER_VENDOR_ID_MESA and GLX_RENDERER_DEVICE_ID_MESA may return + 0xFFFFFFFF if the device does not have a PCI ID (because it is not a PCI + device) or if the PCI ID is not available. In this case the application + should rely on the string query instead. + + If <attribute> is not a recognized value, False is returned, but no GLX + error is generated. Otherwise, True is returned. + + String versions of some attributes may also be queried using + + const char *glXQueryRendererStringMESA(Display *dpy, int screen, + int renderer, int attribute); + + The value for <attribute> will be returned in one or more + integers specified by <value>. The values, data sizes, and descriptions + of each renderer attribute are listed in the table below. + + GLX renderer attribute description + ---------------------- ----------- + GLX_RENDERER_VENDOR_ID_MESA Name of the renderer provider. This may + differ from the vendor name of the + underlying hardware. + GLX_RENDERER_DEVICE_ID_MESA Name of the renderer. This may differ from + the name of the underlying hardware (e.g., + for a software renderer). + + If <attribute> is not a recognized value, NULL is returned, but no GLX + error is generated. + + The string returned for GLX_RENDERER_VENDOR_ID_MESA will have the same + format as the string that would be returned by glGetString of GL_VENDOR. + It may, however, have a different value. + + The string returned for GLX_RENDERER_DEVICE_ID_MESA will have the same + format as the string that would be returned by glGetString of GL_RENDERER. + It may, however, have a different value. + + + [Add to section section 3.3.7 "Rendering Contexts"] + + The attribute name GLX_RENDERER_ID_MESA specified the index of the render + against which the context should be created. The default value of + GLX_RENDER_ID_MESA is 0. + + + [Add to list of errors for glXCreateContextAttribsARB in section section + 3.3.7 "Rendering Contexts"] + + * If the value of GLX_RENDERER_ID_MESA specifies a non-existent + renderer, BadMatch is generated. + +Dependencies on GLX_EXT_create_context_es_profile and +GLX_EXT_create_context_es2_profile + + If neither extension is supported, remove all mention of + GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA from the spec. + + If GLX_EXT_create_context_es_profile is not supported, remove all mention of + GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA from the spec. + +Issues + + 1) How should the difference between on-card and GART memory be exposed? + + UNRESOLVED. + + 2) How should memory limitations of unified memory architecture (UMA) + systems be exposed? + + UNRESOLVED. Some hardware has different per-process and global + limits for memory that can be accessed within a single draw call. + + 3) How should the renderer's API preference be advertised? + + UNRESOLVED. The common case for desktop renderers is to prefer + either core or compatibility. However, some renderers may actually + prefer an ES context. This leaves the application in a tough spot + if it can only support core or compatibility and the renderer says it + wants ES. + + 4) Should OpenGL ES 2.0 and OpenGL ES 3.0 be treated separately? + + RESOLVED. No. OpenGL ES 3.0 is backwards compatible with OpenGL ES + 2.0. Applications can detect OpenGL ES 3.0 support by querying + GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA. + + 5) How can applications tell the difference between different hardware + renderers for the same device? For example, whether the renderer is the + open-source driver or the closed-source driver. + + RESOLVED. Assuming this extension is ever implemented outside Mesa, + applications can query GLX_RENDERER_VENDOR_ID_MESA from + glXQueryRendererStringMESA. This will almost certainly return + different strings for open-source and closed-source drivers. + + 6) What is the value of GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA for + software renderers? + + UNRESOLVED. Video (display) memory and texture memory is not unified + for software implementations, so it seems reasonable for this to be + False. + + 7) How does an application determine the number of available renderers? + + UNRESOLVED. + + 8) What happens if a fbconfig is used to create context on a renderer + that cannot support it? For example, if a multisampled config is used + with a software renderer that does not support multisampling. + + RESOLVED. The language for glXCreateContextAttribsARB already covers + this case. Context creation will fail, and BadMatch is generated. + + 9) In addition to being able to query the supported versions, should + applications also be able to query the supported extensions? + + RESOLVED. No. Desktop OpenGL core profiles and OpenGL ES 3.0 have + moved away from the monolithic string returned by glGetString of + GL_EXTENSIONS. Providing the newer indexed query would require adding + a lot of extra infrastructure, and it would probably provide little + benefit to applications. + + 10) What combination of values for GLX_RENDERER_PREFERRED_PROFILE_MESA, + GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA, and + GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA should be returned + for a renderer that only supports OpenGL 3.1 without the + GL_ARB_compatibility extension? + + RESOLVED. The renderer will return GLX_CONTEXT_CORE_PROFILE_BIT_ARB + for GLX_RENDERER_PREFERRED_PROFILE_MESA. + + Further, the renderer will return <3,0> for + GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA because OpenGL + 3.1 without GL_ARB_compatibility is not backwards compatible with + previous versions of OpenGL. The render will return <3,1> for + GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA indicating that support + for OpenGL 3.1 is available. + + Even though there is no OpenGL 3.1 core profile, the values + returned for GLX_RENDERER_PREFERRED_PROFILE_MESA and + GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA can be supplied + with the GLX_CONTEXT_PROFILE_MASK_ARB and + GLX_CONTEXT_{MAJOR,MINOR}_VERSION_ARB attributes of + glXCreateContextAttribsARB without error. If the requested + OpenGL version is less than 3.2, the + GLX_CONTEXT_PROFILE_MASK_ARB attribute is ignored by + glXCreateContextAttribsARB. + + 11) How can application learn about multi-GPU (e.g., SLI, CrossFireX, + etc.) configurations? + + UNRESOLVED. Based on ISV feedback, this is important information to + provide to the application. Given the variety of possible hardware + configurations (e.g., Hybrid CrossFireX) and different rendering + modes (e.g., split-frame rendering vs. alternate-frame rendering), + it's not clear how this information can be communicated. + + It is likely that this will be left to a layered extension. + + 12) Should capability queries similar to those in + GL_ARB_internalformat_query or GL_ARB_internalformat_query2 be added? + + RESOLVED. No. With the possible exception of the texture size + queries, it seems unlikely that applications would ever use this + information before creating a context. + + 13) Existing GL extensions (e.g., GL_ATI_meminfo and + GL_NVX_gpu_memory_info) allow easy queries after context creation. With + this extension it is a bit of a pain for a portable application to query + the information after context creation. + + RESOLVED. Add versions of the queries that implicitly take the + display, screen, and renderer from the currently bound context. + + 14) Why not make the queries from issue #13 GL functions (instead of GLX)? + + RESOLVED. It is fairly compelling for the post-creation queries to + just use glGetInteger and glGetString. However, the GL enums and + the GLX enums would have different names and would almost certainly + have different values. It seems like this would cause more problems + than it would solve. + + 15) Should the string queries be required to return the same values as + glGetString(GL_VENDOR) and glGetString(GL_RENDERER)? + + UNRESOLVED. This may be useful for applications that already do + device detection based on these strings. + + 16) What type should the value parameter of glXQueryRendererIntegerMESA + and glXQueryCurrentRendererIntegerMESA be? + + UNRESOLVED. Other similar GLX query functions just use int or + unsigned int, so that's what this extension uses for now. However, + an expeclitly sized value, such as uint32_t or uint64_t, seems + preferable. + + 17) What about SoCs and other systems that don't have PCI? + + RESOLVED. The GLX_RENDERER_VENDOR_ID_MESA and + GLX_RENDERER_DEVICE_ID_MESA integer queries may return 0xFFFFFFFF if a + PCI ID either does not exist or is not available. Implementations + should make every attempt to return as much information as is + possible. For example, if the implementation is running on a non-PCI + SoC with a Qualcomm GPU, GLX_RENDERER_VENDOR_ID_MESA should return + 0x168C, but GLX_RENDERER_DEVICE_ID_MESA will return 0x0000. + +Revision History + + Version 1, 2012/08/27 - Initial version + + Version 2, 2012/09/04 - Specify behavior of implementations that + do not support certain profiles. + Change wording of issue #8 to be more + clear. + Make some wording changes to issue #10 to + clarify the resolution a bit. + + Version 3, 2012/09/23 - Add issue #11 regarding multi-GPU systems. + + Version 4, 2013/02/01 - Add issue #12 regarding texture / renderbuffer + format queries. + + Version 5, 2013/02/14 - Add issues #13 and #14 regarding simpler queires + after the context is created and made current. + Add issue #15 regarding the string query. + Add issue #16 regarding the value type returned + by the Integer functions. + + Version 6, 2013/10/25 - Fix a typo. Update the list of functions to + which the new enums can be passed. The "Current" + versions were previously missing. + + Version 7, 2013/11/07 - Fix a couple more typos. Add issue #17 regarding + the PCI queries on systems that don't have PCI. diff --git a/mesalib/include/GL/glx.h b/mesalib/include/GL/glx.h index fa5a8eda9..62d0ede9e 100644 --- a/mesalib/include/GL/glx.h +++ b/mesalib/include/GL/glx.h @@ -467,7 +467,32 @@ extern void glXReleaseTexImageEXT(Display *dpy, GLXDrawable drawable, int buffer #endif /* GLX_EXT_texture_from_pixmap */ - +#ifndef GLX_MESA_query_renderer +#define GLX_MESA_query_renderer 1 + +#define GLX_RENDERER_VENDOR_ID_MESA 0x8183 +#define GLX_RENDERER_DEVICE_ID_MESA 0x8184 +#define GLX_RENDERER_VERSION_MESA 0x8185 +#define GLX_RENDERER_ACCELERATED_MESA 0x8186 +#define GLX_RENDERER_VIDEO_MEMORY_MESA 0x8187 +#define GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA 0x8188 +#define GLX_RENDERER_PREFERRED_PROFILE_MESA 0x8189 +#define GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA 0x818A +#define GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA 0x818B +#define GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA 0x818C +#define GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA 0x818D +#define GLX_RENDERER_ID_MESA 0x818E + +Bool glXQueryRendererIntegerMESA(Display *dpy, int screen, int renderer, int attribute, unsigned int *value); +Bool glXQueryCurrentRendererIntegerMESA(int attribute, unsigned int *value); +const char *glXQueryRendererStringMESA(Display *dpy, int screen, int renderer, int attribute); +const char *glXQueryCurrentRendererStringMESA(int attribute); + +typedef Bool (*PFNGLXQUERYRENDERERINTEGERMESAPROC) (Display *dpy, int screen, int renderer, int attribute, unsigned int *value); +typedef Bool (*PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC) (int attribute, unsigned int *value); +typedef const char *(*PFNGLXQUERYRENDERERSTRINGMESAPROC) (Display *dpy, int screen, int renderer, int attribute); +typedef const char *(*PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC) (int attribute); +#endif /* GLX_MESA_query_renderer */ /*** Should these go here, or in another header? */ /* diff --git a/mesalib/include/GL/internal/dri_interface.h b/mesalib/include/GL/internal/dri_interface.h index 48993b939..ed4325764 100644 --- a/mesalib/include/GL/internal/dri_interface.h +++ b/mesalib/include/GL/internal/dri_interface.h @@ -86,6 +86,10 @@ typedef struct __DRIdri2LoaderExtensionRec __DRIdri2LoaderExtension; typedef struct __DRI2flushExtensionRec __DRI2flushExtension; typedef struct __DRI2throttleExtensionRec __DRI2throttleExtension; + +typedef struct __DRIimageLoaderExtensionRec __DRIimageLoaderExtension; +typedef struct __DRIimageDriverExtensionRec __DRIimageDriverExtension; + /*@}*/ @@ -763,6 +767,40 @@ struct __DRIswrastExtensionRec { }; +/** Common DRI function definitions, shared among DRI2 and Image extensions + */ + +typedef __DRIscreen * +(*__DRIcreateNewScreen2Func)(int screen, int fd, + const __DRIextension **extensions, + const __DRIextension **driver_extensions, + const __DRIconfig ***driver_configs, + void *loaderPrivate); + +typedef __DRIdrawable * +(*__DRIcreateNewDrawableFunc)(__DRIscreen *screen, + const __DRIconfig *config, + void *loaderPrivate); + +typedef __DRIcontext * +(*__DRIcreateNewContextFunc)(__DRIscreen *screen, + const __DRIconfig *config, + __DRIcontext *shared, + void *loaderPrivate); + +typedef __DRIcontext * +(*__DRIcreateContextAttribsFunc)(__DRIscreen *screen, + int api, + const __DRIconfig *config, + __DRIcontext *shared, + unsigned num_attribs, + const uint32_t *attribs, + unsigned *error, + void *loaderPrivate); + +typedef unsigned int +(*__DRIgetAPIMaskFunc)(__DRIscreen *screen); + /** * DRI2 Loader extension. */ @@ -910,17 +948,11 @@ struct __DRIdri2ExtensionRec { const __DRIconfig ***driver_configs, void *loaderPrivate); - __DRIdrawable *(*createNewDrawable)(__DRIscreen *screen, - const __DRIconfig *config, - void *loaderPrivate); - - __DRIcontext *(*createNewContext)(__DRIscreen *screen, - const __DRIconfig *config, - __DRIcontext *shared, - void *loaderPrivate); + __DRIcreateNewDrawableFunc createNewDrawable; + __DRIcreateNewContextFunc createNewContext; /* Since version 2 */ - unsigned int (*getAPIMask)(__DRIscreen *screen); + __DRIgetAPIMaskFunc getAPIMask; __DRIcontext *(*createNewContextForAPI)(__DRIscreen *screen, int api, @@ -943,25 +975,14 @@ struct __DRIdri2ExtensionRec { * * \sa __DRIswrastExtensionRec::createContextAttribs */ - __DRIcontext *(*createContextAttribs)(__DRIscreen *screen, - int api, - const __DRIconfig *config, - __DRIcontext *shared, - unsigned num_attribs, - const uint32_t *attribs, - unsigned *error, - void *loaderPrivate); + __DRIcreateContextAttribsFunc createContextAttribs; /** * createNewScreen with the driver's extension list passed in. * * \since version 4 */ - __DRIscreen *(*createNewScreen2)(int screen, int fd, - const __DRIextension **loader_extensions, - const __DRIextension **driver_extensions, - const __DRIconfig ***driver_configs, - void *loaderPrivate); + __DRIcreateNewScreen2Func createNewScreen2; }; @@ -996,6 +1017,7 @@ struct __DRIdri2ExtensionRec { #define __DRI_IMAGE_FORMAT_NONE 0x1008 #define __DRI_IMAGE_FORMAT_XRGB2101010 0x1009 #define __DRI_IMAGE_FORMAT_ARGB2101010 0x100a +#define __DRI_IMAGE_FORMAT_SARGB8 0x100b #define __DRI_IMAGE_USE_SHARE 0x0001 #define __DRI_IMAGE_USE_SCANOUT 0x0002 @@ -1287,4 +1309,105 @@ typedef struct __DRIDriverVtableExtensionRec { const struct __DriverAPIRec *vtable; } __DRIDriverVtableExtension; +/** + * Query renderer driver extension + * + * This allows the window system layer (either EGL or GLX) to query aspects of + * hardware and driver support without creating a context. + */ +#define __DRI2_RENDERER_QUERY "DRI_RENDERER_QUERY" +#define __DRI2_RENDERER_QUERY_VERSION 1 + +#define __DRI2_RENDERER_VENDOR_ID 0x0000 +#define __DRI2_RENDERER_DEVICE_ID 0x0001 +#define __DRI2_RENDERER_VERSION 0x0002 +#define __DRI2_RENDERER_ACCELERATED 0x0003 +#define __DRI2_RENDERER_VIDEO_MEMORY 0x0004 +#define __DRI2_RENDERER_UNIFIED_MEMORY_ARCHITECTURE 0x0005 +#define __DRI2_RENDERER_PREFERRED_PROFILE 0x0006 +#define __DRI2_RENDERER_OPENGL_CORE_PROFILE_VERSION 0x0007 +#define __DRI2_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION 0x0008 +#define __DRI2_RENDERER_OPENGL_ES_PROFILE_VERSION 0x0009 +#define __DRI2_RENDERER_OPENGL_ES2_PROFILE_VERSION 0x000a + +typedef struct __DRI2rendererQueryExtensionRec __DRI2rendererQueryExtension; +struct __DRI2rendererQueryExtensionRec { + __DRIextension base; + + int (*queryInteger)(__DRIscreen *screen, int attribute, unsigned int *val); + int (*queryString)(__DRIscreen *screen, int attribute, const char **val); +}; + +/** + * Image Loader extension. Drivers use this to allocate color buffers + */ + +enum __DRIimageBufferMask { + __DRI_IMAGE_BUFFER_BACK = (1 << 0), + __DRI_IMAGE_BUFFER_FRONT = (1 << 1) +}; + +struct __DRIimageList { + uint32_t image_mask; + __DRIimage *back; + __DRIimage *front; +}; + +#define __DRI_IMAGE_LOADER "DRI_IMAGE_LOADER" +#define __DRI_IMAGE_LOADER_VERSION 1 + +struct __DRIimageLoaderExtensionRec { + __DRIextension base; + + /** + * Allocate color buffers. + * + * \param driDrawable + * \param width Width of allocated buffers + * \param height Height of allocated buffers + * \param format one of __DRI_IMAGE_FORMAT_* + * \param stamp Address of variable to be updated when + * getBuffers must be called again + * \param loaderPrivate The loaderPrivate for driDrawable + * \param buffer_mask Set of buffers to allocate + * \param buffers Returned buffers + */ + int (*getBuffers)(__DRIdrawable *driDrawable, + unsigned int format, + uint32_t *stamp, + void *loaderPrivate, + uint32_t buffer_mask, + struct __DRIimageList *buffers); + + /** + * Flush pending front-buffer rendering + * + * Any rendering that has been performed to the + * fake front will be flushed to the front + * + * \param driDrawable Drawable whose front-buffer is to be flushed + * \param loaderPrivate Loader's private data that was previously passed + * into __DRIdri2ExtensionRec::createNewDrawable + */ + void (*flushFrontBuffer)(__DRIdrawable *driDrawable, void *loaderPrivate); +}; + +/** + * DRI extension. + */ + +#define __DRI_IMAGE_DRIVER "DRI_IMAGE_DRIVER" +#define __DRI_IMAGE_DRIVER_VERSION 1 + +struct __DRIimageDriverExtensionRec { + __DRIextension base; + + /* Common DRI functions, shared with DRI2 */ + __DRIcreateNewScreen2Func createNewScreen2; + __DRIcreateNewDrawableFunc createNewDrawable; + __DRIcreateNewContextFunc createNewContext; + __DRIcreateContextAttribsFunc createContextAttribs; + __DRIgetAPIMaskFunc getAPIMask; +}; + #endif diff --git a/mesalib/src/gallium/SConscript b/mesalib/src/gallium/SConscript index 9a25ccafb..c68519df0 100644 --- a/mesalib/src/gallium/SConscript +++ b/mesalib/src/gallium/SConscript @@ -45,9 +45,6 @@ if not env['embedded']: if env['dri']: SConscript('state_trackers/dri/SConscript') - if env['dri'] and env['xorg']: - SConscript('state_trackers/xorg/SConscript') - if env['platform'] == 'windows': SConscript('state_trackers/wgl/SConscript') @@ -136,11 +133,6 @@ if not env['embedded']: 'targets/dri-i915/SConscript', ]) - if env['xorg'] and env['drm']: - SConscript([ - #'targets/xorg-i915/SConscript', - ]) - # # Unit tests & tools diff --git a/mesalib/src/gallium/auxiliary/util/u_format.c b/mesalib/src/gallium/auxiliary/util/u_format.c index 9ef3bb53f..6b602bf32 100644 --- a/mesalib/src/gallium/auxiliary/util/u_format.c +++ b/mesalib/src/gallium/auxiliary/util/u_format.c @@ -215,9 +215,8 @@ util_format_is_supported(enum pipe_format format, unsigned bind) * default MRD will be 1.0 / ((1 << 24) - 1). */ double -util_get_depth_format_mrd(enum pipe_format format) +util_get_depth_format_mrd(const struct util_format_description *desc) { - struct util_format_description *format_desc; /* * Depth buffer formats without a depth component OR scenarios * without a bound depth buffer default to D24. @@ -225,23 +224,20 @@ util_get_depth_format_mrd(enum pipe_format format) double mrd = 1.0 / ((1 << 24) - 1); unsigned depth_channel; - format_desc = (struct util_format_description *) - util_format_description(format); - - assert(format_desc); + assert(desc); /* * Some depth formats do not store the depth component in the first * channel, detect the format and adjust the depth channel. Get the * swizzled depth component channel. */ - depth_channel = format_desc->swizzle[0]; + depth_channel = desc->swizzle[0]; - if (format_desc->channel[depth_channel].type == UTIL_FORMAT_TYPE_UNSIGNED && - format_desc->channel[depth_channel].normalized) { + if (desc->channel[depth_channel].type == UTIL_FORMAT_TYPE_UNSIGNED && + desc->channel[depth_channel].normalized) { int depth_bits; - depth_bits = format_desc->channel[depth_channel].size; + depth_bits = desc->channel[depth_channel].size; mrd = 1.0 / ((1ULL << depth_bits) - 1); } diff --git a/mesalib/src/gallium/auxiliary/util/u_format.h b/mesalib/src/gallium/auxiliary/util/u_format.h index 369c3994a..0fbaf4cc1 100644 --- a/mesalib/src/gallium/auxiliary/util/u_format.h +++ b/mesalib/src/gallium/auxiliary/util/u_format.h @@ -546,13 +546,29 @@ util_format_is_depth_and_stencil(enum pipe_format format) /** + * Calculates the depth format type based upon the incoming format description. + */ +static INLINE unsigned +util_get_depth_format_type(const struct util_format_description *desc) +{ + unsigned depth_channel = desc->swizzle[0]; + if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS && + depth_channel != UTIL_FORMAT_SWIZZLE_NONE) { + return desc->channel[depth_channel].type; + } else { + return UTIL_FORMAT_TYPE_VOID; + } +} + + +/** * Calculates the MRD for the depth format. MRD is used in depth bias * for UNORM and unbound depth buffers. When the depth buffer is floating * point, the depth bias calculation does not use the MRD. However, the * default MRD will be 1.0 / ((1 << 24) - 1). */ double -util_get_depth_format_mrd(enum pipe_format format); +util_get_depth_format_mrd(const struct util_format_description *desc); /** diff --git a/mesalib/src/gallium/auxiliary/util/u_math.h b/mesalib/src/gallium/auxiliary/util/u_math.h index f5c14ef8d..426d5daa7 100644 --- a/mesalib/src/gallium/auxiliary/util/u_math.h +++ b/mesalib/src/gallium/auxiliary/util/u_math.h @@ -246,6 +246,19 @@ union di { /** + * Extract the IEEE float32 exponent. + */ +static INLINE signed +util_get_float32_exponent(float x) { + union fi f; + + f.f = x; + + return ((f.ui >> 23) & 0xff) - 127; +} + + +/** * Fast version of 2^x * Identity: exp2(a + b) = exp2(a) * exp2(b) * Let ipart = int(x) diff --git a/mesalib/src/glsl/Makefile.sources b/mesalib/src/glsl/Makefile.sources index 2aabc0585..744b0adcf 100644 --- a/mesalib/src/glsl/Makefile.sources +++ b/mesalib/src/glsl/Makefile.sources @@ -47,6 +47,7 @@ LIBGLSL_FILES = \ $(GLSL_SRCDIR)/ir_validate.cpp \ $(GLSL_SRCDIR)/ir_variable_refcount.cpp \ $(GLSL_SRCDIR)/linker.cpp \ + $(GLSL_SRCDIR)/link_atomics.cpp \ $(GLSL_SRCDIR)/link_functions.cpp \ $(GLSL_SRCDIR)/link_interface_blocks.cpp \ $(GLSL_SRCDIR)/link_uniforms.cpp \ diff --git a/mesalib/src/glsl/ast.h b/mesalib/src/glsl/ast.h index 97905c6a6..5c214b604 100644 --- a/mesalib/src/glsl/ast.h +++ b/mesalib/src/glsl/ast.h @@ -385,6 +385,12 @@ struct ast_type_qualifier { */ unsigned explicit_binding:1; + /** + * Flag set if GL_ARB_shader_atomic counter "offset" layout + * qualifier is used. + */ + unsigned explicit_offset:1; + /** \name Layout qualifiers for GL_AMD_conservative_depth */ /** \{ */ unsigned depth_any:1; @@ -448,6 +454,15 @@ struct ast_type_qualifier { int binding; /** + * Offset specified via GL_ARB_shader_atomic_counter's "offset" + * keyword. + * + * \note + * This field is only valid if \c explicit_offset is set. + */ + int offset; + + /** * Return true if and only if an interpolation qualifier is present. */ bool has_interpolation() const; diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index f75e68ce1..76b256c73 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -1997,10 +1997,20 @@ validate_binding_qualifier(struct _mesa_glsl_parse_state *state, return false; } + } else if (var->type->contains_atomic()) { + assert(ctx->Const.MaxAtomicBufferBindings <= MAX_COMBINED_ATOMIC_BUFFERS); + if (unsigned(qual->binding) >= ctx->Const.MaxAtomicBufferBindings) { + _mesa_glsl_error(loc, state, "layout(binding = %d) exceeds the " + " maximum number of atomic counter buffer bindings" + "(%d)", qual->binding, + ctx->Const.MaxAtomicBufferBindings); + + return false; + } } else { _mesa_glsl_error(loc, state, "the \"binding\" qualifier only applies to uniform " - "blocks, samplers, or arrays of samplers"); + "blocks, samplers, atomic counters, or arrays thereof"); return false; } @@ -2300,6 +2310,29 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, var->binding = qual->binding; } + if (var->type->contains_atomic()) { + if (var->mode == ir_var_uniform) { + if (var->explicit_binding) { + unsigned *offset = &state->atomic_counter_offsets[var->binding]; + + if (*offset % ATOMIC_COUNTER_SIZE) + _mesa_glsl_error(loc, state, + "misaligned atomic counter offset"); + + var->atomic.offset = *offset; + *offset += var->type->atomic_size(); + + } else { + _mesa_glsl_error(loc, state, + "atomic counters require explicit binding point"); + } + } else if (var->mode != ir_var_function_in) { + _mesa_glsl_error(loc, state, "atomic counters may only be declared as " + "function parameters or uniform-qualified " + "global variables"); + } + } + /* Does the declaration use the deprecated 'attribute' or 'varying' * keywords? */ @@ -2835,6 +2868,18 @@ ast_declarator_list::hir(exec_list *instructions, (void) this->type->specifier->hir(instructions, state); decl_type = this->type->glsl_type(& type_name, state); + + /* An offset-qualified atomic counter declaration sets the default + * offset for the next declaration within the same atomic counter + * buffer. + */ + if (decl_type && decl_type->contains_atomic()) { + if (type->qualifier.flags.q.explicit_binding && + type->qualifier.flags.q.explicit_offset) + state->atomic_counter_offsets[type->qualifier.binding] = + type->qualifier.offset; + } + if (this->declarations.is_empty()) { /* If there is no structure involved in the program text, there are two * possible scenarios: @@ -2864,6 +2909,11 @@ ast_declarator_list::hir(exec_list *instructions, _mesa_glsl_error(&loc, state, "invalid type `%s' in empty declaration", type_name); + } else if (decl_type->base_type == GLSL_TYPE_ATOMIC_UINT) { + /* Empty atomic counter declarations are allowed and useful + * to set the default offset qualifier. + */ + return NULL; } else if (this->type->qualifier.precision != ast_precision_none) { if (this->type->specifier->structure != NULL) { _mesa_glsl_error(&loc, state, @@ -4565,6 +4615,17 @@ ast_process_structure_or_interface_block(exec_list *instructions, "uniform in non-default uniform block contains sampler"); } + if (field_type->contains_atomic()) { + /* FINISHME: Add a spec quotation here once updated spec + * FINISHME: language is available. See Khronos bug #10903 + * FINISHME: on whether atomic counters are allowed in + * FINISHME: structures. + */ + YYLTYPE loc = decl_list->get_location(); + _mesa_glsl_error(&loc, state, "atomic counter in structure or " + "uniform block"); + } + const struct ast_type_qualifier *const qual = & decl_list->type->qualifier; if (qual->flags.q.std140 || diff --git a/mesalib/src/glsl/ast_type.cpp b/mesalib/src/glsl/ast_type.cpp index 8aabd95f9..2b088bf8b 100644 --- a/mesalib/src/glsl/ast_type.cpp +++ b/mesalib/src/glsl/ast_type.cpp @@ -72,7 +72,8 @@ ast_type_qualifier::has_layout() const || this->flags.q.packed || this->flags.q.explicit_location || this->flags.q.explicit_index - || this->flags.q.explicit_binding; + || this->flags.q.explicit_binding + || this->flags.q.explicit_offset; } bool @@ -121,13 +122,18 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc, ubo_layout_mask.flags.q.packed = 1; ubo_layout_mask.flags.q.shared = 1; + ast_type_qualifier ubo_binding_mask; + ubo_binding_mask.flags.q.explicit_binding = 1; + ubo_binding_mask.flags.q.explicit_offset = 1; + /* Uniform block layout qualifiers get to overwrite each * other (rightmost having priority), while all other * qualifiers currently don't allow duplicates. */ if ((this->flags.i & q.flags.i & ~(ubo_mat_mask.flags.i | - ubo_layout_mask.flags.i)) != 0) { + ubo_layout_mask.flags.i | + ubo_binding_mask.flags.i)) != 0) { _mesa_glsl_error(loc, state, "duplicate layout qualifiers used"); return false; @@ -168,6 +174,9 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc, if (q.flags.q.explicit_binding) this->binding = q.binding; + if (q.flags.q.explicit_offset) + this->offset = q.offset; + if (q.precision != ast_precision_none) this->precision = q.precision; diff --git a/mesalib/src/glsl/builtin_functions.cpp b/mesalib/src/glsl/builtin_functions.cpp index 3fa0cb5ad..8cb75e5ad 100644 --- a/mesalib/src/glsl/builtin_functions.cpp +++ b/mesalib/src/glsl/builtin_functions.cpp @@ -293,7 +293,8 @@ static bool fs_oes_derivatives(const _mesa_glsl_parse_state *state) { return state->target == fragment_shader && - (!state->es_shader || state->OES_standard_derivatives_enable); + (state->is_version(110, 300) || + state->OES_standard_derivatives_enable); } static bool diff --git a/mesalib/src/glsl/glsl_lexer.ll b/mesalib/src/glsl/glsl_lexer.ll index e24df8096..822d70d6b 100644 --- a/mesalib/src/glsl/glsl_lexer.ll +++ b/mesalib/src/glsl/glsl_lexer.ll @@ -337,6 +337,7 @@ samplerExternalOES { return IDENTIFIER; } +atomic_uint KEYWORD_WITH_ALT(420, 300, 420, 0, yyextra->ARB_shader_atomic_counters_enable, ATOMIC_UINT); struct return STRUCT; void return VOID_TOK; @@ -518,7 +519,6 @@ restrict KEYWORD(0, 300, 0, 0, RESTRICT); readonly KEYWORD(0, 300, 0, 0, READONLY); writeonly KEYWORD(0, 300, 0, 0, WRITEONLY); resource KEYWORD(0, 300, 0, 0, RESOURCE); -atomic_uint KEYWORD(0, 300, 0, 0, ATOMIC_UINT); patch KEYWORD(0, 300, 0, 0, PATCH); sample KEYWORD(0, 300, 0, 0, SAMPLE); subroutine KEYWORD(0, 300, 0, 0, SUBROUTINE); diff --git a/mesalib/src/glsl/glsl_parser.yy b/mesalib/src/glsl/glsl_parser.yy index 14420f8a3..ada3690f6 100644 --- a/mesalib/src/glsl/glsl_parser.yy +++ b/mesalib/src/glsl/glsl_parser.yy @@ -144,6 +144,7 @@ static bool match_layout_qualifier(const char *s1, const char *s2, %token SAMPLER2DMS ISAMPLER2DMS USAMPLER2DMS %token SAMPLER2DMSARRAY ISAMPLER2DMSARRAY USAMPLER2DMSARRAY %token SAMPLEREXTERNALOES +%token ATOMIC_UINT %token STRUCT VOID_TOK WHILE %token <identifier> IDENTIFIER TYPE_IDENTIFIER NEW_IDENTIFIER %type <identifier> any_identifier @@ -173,7 +174,7 @@ static bool match_layout_qualifier(const char *s1, const char *s2, %token HVEC2 HVEC3 HVEC4 DVEC2 DVEC3 DVEC4 FVEC2 FVEC3 FVEC4 %token SAMPLER3DRECT %token SIZEOF CAST NAMESPACE USING -%token COHERENT RESTRICT READONLY WRITEONLY RESOURCE ATOMIC_UINT PATCH SAMPLE +%token COHERENT RESTRICT READONLY WRITEONLY RESOURCE PATCH SAMPLE %token SUBROUTINE %token ERROR_TOK @@ -1324,12 +1325,19 @@ layout_qualifier_id: } } - if (state->ARB_shading_language_420pack_enable && + if ((state->ARB_shading_language_420pack_enable || + state->ARB_shader_atomic_counters_enable) && match_layout_qualifier("binding", $1, state) == 0) { $$.flags.q.explicit_binding = 1; $$.binding = $3; } + if (state->ARB_shader_atomic_counters_enable && + match_layout_qualifier("offset", $1, state) == 0) { + $$.flags.q.explicit_offset = 1; + $$.offset = $3; + } + if (match_layout_qualifier("max_vertices", $1, state) == 0) { $$.flags.q.max_vertices = 1; @@ -1703,6 +1711,7 @@ basic_type_specifier_nonarray: | SAMPLER2DMSARRAY { $$ = "sampler2DMSArray"; } | ISAMPLER2DMSARRAY { $$ = "isampler2DMSArray"; } | USAMPLER2DMSARRAY { $$ = "usampler2DMSArray"; } + | ATOMIC_UINT { $$ = "atomic_uint"; } ; precision_qualifier: diff --git a/mesalib/src/glsl/glsl_parser_extras.h b/mesalib/src/glsl/glsl_parser_extras.h index 345d7a018..d232bb3f6 100644 --- a/mesalib/src/glsl/glsl_parser_extras.h +++ b/mesalib/src/glsl/glsl_parser_extras.h @@ -373,6 +373,9 @@ struct _mesa_glsl_parse_state { * Unused for other shader types. */ unsigned gs_input_size; + + /** Atomic counter offsets by binding */ + unsigned atomic_counter_offsets[MAX_COMBINED_ATOMIC_BUFFERS]; }; # define YYLLOC_DEFAULT(Current, Rhs, N) \ diff --git a/mesalib/src/glsl/link_atomics.cpp b/mesalib/src/glsl/link_atomics.cpp new file mode 100644 index 000000000..2466bbd79 --- /dev/null +++ b/mesalib/src/glsl/link_atomics.cpp @@ -0,0 +1,277 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "ir.h" +#include "ir_uniform.h" +#include "linker.h" +#include "program/hash_table.h" +#include "main/macros.h" + +namespace { + /* + * Atomic counter as seen by the program. + */ + struct active_atomic_counter { + unsigned id; + ir_variable *var; + }; + + /* + * Atomic counter buffer referenced by the program. There is a one + * to one correspondence between these and the objects that can be + * queried using glGetActiveAtomicCounterBufferiv(). + */ + struct active_atomic_buffer { + active_atomic_buffer() + : counters(0), num_counters(0), stage_references(), size(0) + {} + + ~active_atomic_buffer() + { + free(counters); + } + + void push_back(unsigned id, ir_variable *var) + { + counters = (active_atomic_counter *) + realloc(counters, sizeof(active_atomic_counter) * (num_counters + 1)); + + counters[num_counters].id = id; + counters[num_counters].var = var; + num_counters++; + } + + active_atomic_counter *counters; + unsigned num_counters; + unsigned stage_references[MESA_SHADER_TYPES]; + unsigned size; + }; + + int + cmp_actives(const void *a, const void *b) + { + const active_atomic_counter *const first = (active_atomic_counter *) a; + const active_atomic_counter *const second = (active_atomic_counter *) b; + + return int(first->var->atomic.offset) - int(second->var->atomic.offset); + } + + bool + check_atomic_counters_overlap(const ir_variable *x, const ir_variable *y) + { + return ((x->atomic.offset >= y->atomic.offset && + x->atomic.offset < y->atomic.offset + y->type->atomic_size()) || + (y->atomic.offset >= x->atomic.offset && + y->atomic.offset < x->atomic.offset + x->type->atomic_size())); + } + + active_atomic_buffer * + find_active_atomic_counters(struct gl_context *ctx, + struct gl_shader_program *prog, + unsigned *num_buffers) + { + active_atomic_buffer *const buffers = + new active_atomic_buffer[ctx->Const.MaxAtomicBufferBindings]; + + *num_buffers = 0; + + for (unsigned i = 0; i < MESA_SHADER_TYPES; ++i) { + struct gl_shader *sh = prog->_LinkedShaders[i]; + if (sh == NULL) + continue; + + foreach_list(node, sh->ir) { + ir_variable *var = ((ir_instruction *)node)->as_variable(); + + if (var && var->type->contains_atomic()) { + unsigned id; + bool found = prog->UniformHash->get(id, var->name); + assert(found); + active_atomic_buffer *buf = &buffers[var->binding]; + + /* If this is the first time the buffer is used, increment + * the counter of buffers used. + */ + if (buf->size == 0) + (*num_buffers)++; + + buf->push_back(id, var); + + buf->stage_references[i]++; + buf->size = MAX2(buf->size, var->atomic.offset + + var->type->atomic_size()); + } + } + } + + for (unsigned i = 0; i < ctx->Const.MaxAtomicBufferBindings; i++) { + if (buffers[i].size == 0) + continue; + + qsort(buffers[i].counters, buffers[i].num_counters, + sizeof(active_atomic_counter), + cmp_actives); + + for (unsigned j = 1; j < buffers[i].num_counters; j++) { + /* If an overlapping counter found, it must be a reference to the + * same counter from a different shader stage. + */ + if (check_atomic_counters_overlap(buffers[i].counters[j-1].var, + buffers[i].counters[j].var) + && strcmp(buffers[i].counters[j-1].var->name, + buffers[i].counters[j].var->name) != 0) { + linker_error(prog, "Atomic counter %s declared at offset %d " + "which is already in use.", + buffers[i].counters[j].var->name, + buffers[i].counters[j].var->atomic.offset); + } + } + } + return buffers; + } +} + +void +link_assign_atomic_counter_resources(struct gl_context *ctx, + struct gl_shader_program *prog) +{ + unsigned num_buffers; + active_atomic_buffer *abs = + find_active_atomic_counters(ctx, prog, &num_buffers); + + prog->AtomicBuffers = rzalloc_array(prog, gl_active_atomic_buffer, + num_buffers); + prog->NumAtomicBuffers = num_buffers; + + unsigned i = 0; + for (unsigned binding = 0; + binding < ctx->Const.MaxAtomicBufferBindings; + binding++) { + + /* If the binding was not used, skip. + */ + if (abs[binding].size == 0) + continue; + + active_atomic_buffer &ab = abs[binding]; + gl_active_atomic_buffer &mab = prog->AtomicBuffers[i]; + + /* Assign buffer-specific fields. */ + mab.Binding = binding; + mab.MinimumSize = ab.size; + mab.Uniforms = rzalloc_array(prog->AtomicBuffers, GLuint, + ab.num_counters); + mab.NumUniforms = ab.num_counters; + + /* Assign counter-specific fields. */ + for (unsigned j = 0; j < ab.num_counters; j++) { + ir_variable *const var = ab.counters[j].var; + const unsigned id = ab.counters[j].id; + gl_uniform_storage *const storage = &prog->UniformStorage[id]; + + mab.Uniforms[j] = id; + var->atomic.buffer_index = i; + storage->atomic_buffer_index = i; + storage->offset = var->atomic.offset; + storage->array_stride = (var->type->is_array() ? + var->type->element_type()->atomic_size() : 0); + } + + /* Assign stage-specific fields. */ + for (unsigned j = 0; j < MESA_SHADER_TYPES; ++j) + mab.StageReferences[j] = + (ab.stage_references[j] ? GL_TRUE : GL_FALSE); + + i++; + } + + delete [] abs; + assert(i == num_buffers); +} + +void +link_check_atomic_counter_resources(struct gl_context *ctx, + struct gl_shader_program *prog) +{ + STATIC_ASSERT(MESA_SHADER_TYPES == 3); + static const char *shader_names[MESA_SHADER_TYPES] = { + "vertex", "geometry", "fragment" + }; + const unsigned max_atomic_counters[MESA_SHADER_TYPES] = { + ctx->Const.VertexProgram.MaxAtomicCounters, + ctx->Const.GeometryProgram.MaxAtomicCounters, + ctx->Const.FragmentProgram.MaxAtomicCounters + }; + const unsigned max_atomic_buffers[MESA_SHADER_TYPES] = { + ctx->Const.VertexProgram.MaxAtomicBuffers, + ctx->Const.GeometryProgram.MaxAtomicBuffers, + ctx->Const.FragmentProgram.MaxAtomicBuffers + }; + unsigned num_buffers; + active_atomic_buffer *const abs = + find_active_atomic_counters(ctx, prog, &num_buffers); + unsigned atomic_counters[MESA_SHADER_TYPES] = {}; + unsigned atomic_buffers[MESA_SHADER_TYPES] = {}; + unsigned total_atomic_counters = 0; + unsigned total_atomic_buffers = 0; + + /* Sum the required resources. Note that this counts buffers and + * counters referenced by several shader stages multiple times + * against the combined limit -- That's the behavior the spec + * requires. + */ + for (unsigned i = 0; i < ctx->Const.MaxAtomicBufferBindings; i++) { + if (abs[i].size == 0) + continue; + + for (unsigned j = 0; j < MESA_SHADER_TYPES; ++j) { + const unsigned n = abs[i].stage_references[j]; + + if (n) { + atomic_counters[j] += n; + total_atomic_counters += n; + atomic_buffers[j]++; + total_atomic_buffers++; + } + } + } + + /* Check that they are within the supported limits. */ + for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) { + if (atomic_counters[i] > max_atomic_counters[i]) + linker_error(prog, "Too many %s shader atomic counters", + shader_names[i]); + + if (atomic_buffers[i] > max_atomic_buffers[i]) + linker_error(prog, "Too many %s shader atomic counter buffers", + shader_names[i]); + } + + if (total_atomic_counters > ctx->Const.MaxCombinedAtomicCounters) + linker_error(prog, "Too many combined atomic counters"); + + if (total_atomic_buffers > ctx->Const.MaxCombinedAtomicBuffers) + linker_error(prog, "Too many combined atomic buffers"); + + delete [] abs; +} diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp index 49bb142a8..1d53b6599 100644 --- a/mesalib/src/glsl/linker.cpp +++ b/mesalib/src/glsl/linker.cpp @@ -651,6 +651,14 @@ cross_validate_globals(struct gl_shader_program *prog, existing->explicit_binding = true; } + if (var->type->contains_atomic() && + var->atomic.offset != existing->atomic.offset) { + linker_error(prog, "offset specifications for %s " + "`%s' have differing values\n", + mode_string(var), var->name); + return; + } + /* Validate layout qualifiers for gl_FragDepth. * * From the AMD/ARB_conservative_depth specs: @@ -1485,8 +1493,12 @@ update_array_sizes(struct gl_shader_program *prog) /* GL_ARB_uniform_buffer_object says that std140 uniforms * will not be eliminated. Since we always do std140, just * don't resize arrays in UBOs. + * + * Atomic counters are supposed to get deterministic + * locations assigned based on the declaration ordering and + * sizes, array compaction would mess that up. */ - if (var->is_in_uniform_block()) + if (var->is_in_uniform_block() || var->type->contains_atomic()) continue; unsigned int size = var->max_array_access; @@ -1991,6 +2003,10 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) prog->UniformBlockStageIndex[i] = NULL; } + ralloc_free(prog->AtomicBuffers); + prog->AtomicBuffers = NULL; + prog->NumAtomicBuffers = 0; + /* Separate the shaders into groups based on their type. */ struct gl_shader **vert_shader_list; @@ -2342,9 +2358,12 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) update_array_sizes(prog); link_assign_uniform_locations(prog); + link_assign_atomic_counter_resources(ctx, prog); store_fragdepth_layout(prog); check_resources(ctx, prog); + link_check_atomic_counter_resources(ctx, prog); + if (!prog->LinkStatus) goto done; diff --git a/mesalib/src/glsl/linker.h b/mesalib/src/glsl/linker.h index 887cd33d1..7b1f6f9c5 100644 --- a/mesalib/src/glsl/linker.h +++ b/mesalib/src/glsl/linker.h @@ -69,6 +69,14 @@ validate_interstage_interface_blocks(struct gl_shader_program *prog, const gl_shader *producer, const gl_shader *consumer); +extern void +link_assign_atomic_counter_resources(struct gl_context *ctx, + struct gl_shader_program *prog); + +extern void +link_check_atomic_counter_resources(struct gl_context *ctx, + struct gl_shader_program *prog); + /** * Class for processing all of the leaf fields of a variable that corresponds * to a program resource. diff --git a/mesalib/src/mapi/glapi/Makefile.am b/mesalib/src/mapi/glapi/Makefile.am index 05c67a6d4..bf653a305 100644 --- a/mesalib/src/mapi/glapi/Makefile.am +++ b/mesalib/src/mapi/glapi/Makefile.am @@ -33,10 +33,11 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/mesa if HAVE_X86_ASM -GLAPI_ASM_SOURCES = $(X86_API) -endif if HAVE_X86_64_ASM GLAPI_ASM_SOURCES = $(X86_64_API) +else +GLAPI_ASM_SOURCES = $(X86_API) +endif endif if HAVE_SPARC_ASM GLAPI_ASM_SOURCES = $(SPARC_API) diff --git a/mesalib/src/mapi/glapi/gen/ARB_vertex_attrib_binding.xml b/mesalib/src/mapi/glapi/gen/ARB_vertex_attrib_binding.xml new file mode 100644 index 000000000..0ee6a3c00 --- /dev/null +++ b/mesalib/src/mapi/glapi/gen/ARB_vertex_attrib_binding.xml @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<!DOCTYPE OpenGLAPI SYSTEM "gl_API.dtd"> + +<!-- Note: no GLX protocol info yet. --> + +<OpenGLAPI> + +<category name="GL_ARB_vertex_attrib_binding" number="125"> + + <function name="BindVertexBuffer" offset="assign"> + <param name="bindingindex" type="GLuint"/> + <param name="buffer" type="GLuint"/> + <param name="offset" type="GLintptr"/> + <param name="stride" type="GLsizei"/> + </function> + + <function name="VertexAttribFormat" offset="assign"> + <param name="attribindex" type="GLuint"/> + <param name="size" type="GLint"/> + <param name="type" type="GLenum"/> + <param name="normalized" type="GLboolean"/> + <param name="relativeoffset" type="GLuint"/> + </function> + + <function name="VertexAttribIFormat" offset="assign"> + <param name="attribindex" type="GLuint"/> + <param name="size" type="GLint"/> + <param name="type" type="GLenum"/> + <param name="relativeoffset" type="GLuint"/> + </function> + + <function name="VertexAttribLFormat" offset="assign"> + <param name="attribindex" type="GLuint"/> + <param name="size" type="GLint"/> + <param name="type" type="GLenum"/> + <param name="relativeoffset" type="GLuint"/> + </function> + + <function name="VertexAttribBinding" offset="assign"> + <param name="attribindex" type="GLuint"/> + <param name="bindingindex" type="GLuint"/> + </function> + + <function name="VertexBindingDivisor" offset="assign"> + <param name="attribindex" type="GLuint"/> + <param name="divisor" type="GLuint"/> + </function> + + <enum name="VERTEX_ATTRIB_BINDING" value="0x82D4"/> + <enum name="VERTEX_ATTRIB_RELATIVE_OFFSET" value="0x82D5"/> + <enum name="VERTEX_BINDING_DIVISOR" value="0x82D6"/> + <enum name="VERTEX_BINDING_OFFSET" value="0x82D7"/> + <enum name="VERTEX_BINDING_STRIDE" value="0x82D8"/> + <enum name="MAX_VERTEX_ATTRIB_RELATIVE_OFFSET" value="0x82D9"/> + <enum name="MAX_VERTEX_ATTRIB_BINDINGS" value="0x82DA"/> + +</category> +</OpenGLAPI> diff --git a/mesalib/src/mapi/glapi/gen/Makefile.am b/mesalib/src/mapi/glapi/gen/Makefile.am index cbbf659dd..476d943dd 100644 --- a/mesalib/src/mapi/glapi/gen/Makefile.am +++ b/mesalib/src/mapi/glapi/gen/Makefile.am @@ -32,11 +32,11 @@ MESA_GLAPI_OUTPUTS = \ MESA_GLAPI_ASM_OUTPUTS = if HAVE_X86_ASM -MESA_GLAPI_ASM_OUTPUTS += $(MESA_GLAPI_DIR)/glapi_x86.S -endif - if HAVE_X86_64_ASM MESA_GLAPI_ASM_OUTPUTS += $(MESA_GLAPI_DIR)/glapi_x86-64.S +else +MESA_GLAPI_ASM_OUTPUTS += $(MESA_GLAPI_DIR)/glapi_x86.S +endif endif if HAVE_SPARC_ASM @@ -125,6 +125,7 @@ API_XML = \ ARB_texture_storage_multisample.xml \ ARB_texture_storage.xml \ ARB_vertex_array_object.xml \ + ARB_vertex_attrib_binding.xml \ AMD_draw_buffers_blend.xml \ AMD_performance_monitor.xml \ ARB_vertex_type_2_10_10_10_rev.xml \ diff --git a/mesalib/src/mapi/glapi/gen/gl_API.xml b/mesalib/src/mapi/glapi/gen/gl_API.xml index 69014c5d2..a2d914ac4 100644 --- a/mesalib/src/mapi/glapi/gen/gl_API.xml +++ b/mesalib/src/mapi/glapi/gen/gl_API.xml @@ -8458,7 +8458,11 @@ </category> -<!-- ARB extensions #120...#126 --> +<!-- ARB extensions #120...#124 --> + +<xi:include href="ARB_vertex_attrib_binding.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/> + +<!-- ARB extension #126 --> <xi:include href="ARB_ES3_compatibility.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/> diff --git a/mesalib/src/mesa/x86/.gitignore b/mesalib/src/mesa/.gitignore index ca3130d9f..ca3130d9f 100644 --- a/mesalib/src/mesa/x86/.gitignore +++ b/mesalib/src/mesa/.gitignore diff --git a/mesalib/src/mesa/Makefile.am b/mesalib/src/mesa/Makefile.am index a54b8ac1b..a60600e03 100644 --- a/mesalib/src/mesa/Makefile.am +++ b/mesalib/src/mesa/Makefile.am @@ -19,7 +19,7 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. -SUBDIRS = x86 x86-64 . main/tests +SUBDIRS = . main/tests if HAVE_X11_DRIVER SUBDIRS += drivers/x11 @@ -81,7 +81,7 @@ main/get_hash.h: $(GLAPI)/gl_and_es_API.xml main/get_hash_params.py \ -f $< > $@.tmp; \ mv $@.tmp $@; -noinst_LTLIBRARIES = +noinst_LTLIBRARIES = $(ARCH_LIBS) if NEED_LIBMESA noinst_LTLIBRARIES += libmesa.la else @@ -98,12 +98,20 @@ AM_CXXFLAGS = $(LLVM_CFLAGS) $(VISIBILITY_CXXFLAGS) MESA_ASM_FILES_FOR_ARCH = if HAVE_X86_ASM -MESA_ASM_FILES_FOR_ARCH += $(X86_FILES) -AM_CPPFLAGS += -I$(builddir)/x86 -I$(srcdir)/x86 -endif +noinst_PROGRAMS = gen_matypes + +gen_matypes_SOURCES = x86/gen_matypes.c +BUILT_SOURCES += matypes.h + +ARCH_LIBS = libmesa_sse41.la + if HAVE_X86_64_ASM MESA_ASM_FILES_FOR_ARCH += $(X86_64_FILES) AM_CPPFLAGS += -I$(builddir)/x86-64 -I$(srcdir)/x86-64 +else +MESA_ASM_FILES_FOR_ARCH += $(X86_FILES) +AM_CPPFLAGS += -I$(builddir)/x86 -I$(srcdir)/x86 +endif endif if HAVE_SPARC_ASM MESA_ASM_FILES_FOR_ARCH += $(SPARC_FILES) @@ -117,6 +125,7 @@ libmesa_la_SOURCES = \ libmesa_la_LIBADD = \ $(top_builddir)/src/glsl/libglsl.la \ + $(ARCH_LIBS) \ $() libmesagallium_la_SOURCES = \ @@ -126,8 +135,13 @@ libmesagallium_la_SOURCES = \ libmesagallium_la_LIBADD = \ $(top_builddir)/src/glsl/libglsl.la \ + $(ARCH_LIBS) \ $() +libmesa_sse41_la_SOURCES = \ + main/streaming-load-memcpy.c +libmesa_sse41_la_CFLAGS = $(AM_CFLAGS) -msse4.1 + pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = gl.pc @@ -139,6 +153,15 @@ $(BUILDDIR)program/program_parse.tab.c $(BUILDDIR)program/program_parse.tab.h: p $(MKDIR_P) $(builddir)/program $(AM_V_GEN) $(YACC) -p "_mesa_program_" -v -d --output=$(BUILDDIR)program/program_parse.tab.c $< +if GEN_ASM_OFFSETS +matypes.h: $(gen_matypes_SOURCES) + $(AM_V_GEN)$(COMPILE) $< -DASM_OFFSETS -S -o - | \ + sed -n '/^->/{s:^->::;/[$$]/{s:^:#define :;s:[$$]::};p}' > $@ +else +matypes.h: gen_matypes + $(AM_V_GEN)./gen_matypes > $@ +endif + # Emacs tags tags: etags `find . -name \*.[ch]` $(top_srcdir)/include/GL/*.h diff --git a/mesalib/src/mesa/drivers/dri/common/dri_util.c b/mesalib/src/mesa/drivers/dri/common/dri_util.c index c28b0fc41..86cf24cb8 100644 --- a/mesalib/src/mesa/drivers/dri/common/dri_util.c +++ b/mesalib/src/mesa/drivers/dri/common/dri_util.c @@ -78,6 +78,8 @@ setupLoaderExtensions(__DRIscreen *psp, psp->dri2.useInvalidate = (__DRIuseInvalidateExtension *) extensions[i]; if (strcmp(extensions[i]->name, __DRI_SWRAST_LOADER) == 0) psp->swrast_loader = (__DRIswrastLoaderExtension *) extensions[i]; + if (strcmp(extensions[i]->name, __DRI_IMAGE_LOADER) == 0) + psp->image.loader = (__DRIimageLoaderExtension *) extensions[i]; } } @@ -106,10 +108,10 @@ const struct __DriverAPIRec *globalDriverAPI = &driDriverAPI; * Display. */ static __DRIscreen * -dri2CreateNewScreen2(int scrn, int fd, - const __DRIextension **extensions, - const __DRIextension **driver_extensions, - const __DRIconfig ***driver_configs, void *data) +driCreateNewScreen2(int scrn, int fd, + const __DRIextension **extensions, + const __DRIextension **driver_extensions, + const __DRIconfig ***driver_configs, void *data) { static const __DRIextension *emptyExtensionList[] = { NULL }; __DRIscreen *psp; @@ -190,7 +192,7 @@ dri2CreateNewScreen(int scrn, int fd, const __DRIextension **extensions, const __DRIconfig ***driver_configs, void *data) { - return dri2CreateNewScreen2(scrn, fd, extensions, NULL, + return driCreateNewScreen2(scrn, fd, extensions, NULL, driver_configs, data); } @@ -199,7 +201,7 @@ static __DRIscreen * driSWRastCreateNewScreen(int scrn, const __DRIextension **extensions, const __DRIconfig ***driver_configs, void *data) { - return dri2CreateNewScreen2(scrn, -1, extensions, NULL, + return driCreateNewScreen2(scrn, -1, extensions, NULL, driver_configs, data); } @@ -208,7 +210,7 @@ driSWRastCreateNewScreen2(int scrn, const __DRIextension **extensions, const __DRIextension **driver_extensions, const __DRIconfig ***driver_configs, void *data) { - return dri2CreateNewScreen2(scrn, -1, extensions, driver_extensions, + return driCreateNewScreen2(scrn, -1, extensions, driver_extensions, driver_configs, data); } @@ -291,13 +293,13 @@ validate_context_version(__DRIscreen *screen, /*@{*/ static __DRIcontext * -dri2CreateContextAttribs(__DRIscreen *screen, int api, - const __DRIconfig *config, - __DRIcontext *shared, - unsigned num_attribs, - const uint32_t *attribs, - unsigned *error, - void *data) +driCreateContextAttribs(__DRIscreen *screen, int api, + const __DRIconfig *config, + __DRIcontext *shared, + unsigned num_attribs, + const uint32_t *attribs, + unsigned *error, + void *data) { __DRIcontext *context; const struct gl_config *modes = (config != NULL) ? &config->modes : NULL; @@ -306,6 +308,7 @@ dri2CreateContextAttribs(__DRIscreen *screen, int api, unsigned major_version = 1; unsigned minor_version = 0; uint32_t flags = 0; + bool notify_reset = false; assert((num_attribs == 0) || (attribs != NULL)); @@ -344,6 +347,10 @@ dri2CreateContextAttribs(__DRIscreen *screen, int api, case __DRI_CTX_ATTRIB_FLAGS: flags = attribs[i * 2 + 1]; break; + case __DRI_CTX_ATTRIB_RESET_STRATEGY: + notify_reset = (attribs[i * 2 + 1] + != __DRI_CTX_RESET_NO_NOTIFICATION); + break; default: /* We can't create a context that satisfies the requirements of an * attribute that we don't understand. Return failure. @@ -424,7 +431,7 @@ dri2CreateContextAttribs(__DRIscreen *screen, int api, if (!screen->driver->CreateContext(mesa_api, modes, context, major_version, minor_version, - flags, error, shareCtx) ) { + flags, notify_reset, error, shareCtx)) { free(context); return NULL; } @@ -442,22 +449,22 @@ dri2CreateContextAttribs(__DRIscreen *screen, int api, } static __DRIcontext * -dri2CreateNewContextForAPI(__DRIscreen *screen, int api, - const __DRIconfig *config, - __DRIcontext *shared, void *data) +driCreateNewContextForAPI(__DRIscreen *screen, int api, + const __DRIconfig *config, + __DRIcontext *shared, void *data) { unsigned error; - return dri2CreateContextAttribs(screen, api, config, shared, 0, NULL, - &error, data); + return driCreateContextAttribs(screen, api, config, shared, 0, NULL, + &error, data); } static __DRIcontext * -dri2CreateNewContext(__DRIscreen *screen, const __DRIconfig *config, - __DRIcontext *shared, void *data) +driCreateNewContext(__DRIscreen *screen, const __DRIconfig *config, + __DRIcontext *shared, void *data) { - return dri2CreateNewContextForAPI(screen, __DRI_API_OPENGL, - config, shared, data); + return driCreateNewContextForAPI(screen, __DRI_API_OPENGL, + config, shared, data); } /** @@ -609,9 +616,9 @@ static void dri_put_drawable(__DRIdrawable *pdp) } static __DRIdrawable * -dri2CreateNewDrawable(__DRIscreen *screen, - const __DRIconfig *config, - void *data) +driCreateNewDrawable(__DRIscreen *screen, + const __DRIconfig *config, + void *data) { __DRIdrawable *pdraw; @@ -698,7 +705,7 @@ dri2ConfigQueryf(__DRIscreen *screen, const char *var, GLfloat *val) } static unsigned int -dri2GetAPIMask(__DRIscreen *screen) +driGetAPIMask(__DRIscreen *screen) { return screen->api_mask; } @@ -729,7 +736,7 @@ const __DRIcoreExtension driCoreExtension = { .createNewDrawable = NULL, .destroyDrawable = driDestroyDrawable, .swapBuffers = driSwapBuffers, /* swrast */ - .createNewContext = dri2CreateNewContext, /* swrast */ + .createNewContext = driCreateNewContext, /* swrast */ .copyContext = driCopyContext, .destroyContext = driDestroyContext, .bindContext = driBindContext, @@ -741,22 +748,22 @@ const __DRIdri2Extension driDRI2Extension = { .base = { __DRI_DRI2, 4 }, .createNewScreen = dri2CreateNewScreen, - .createNewDrawable = dri2CreateNewDrawable, - .createNewContext = dri2CreateNewContext, - .getAPIMask = dri2GetAPIMask, - .createNewContextForAPI = dri2CreateNewContextForAPI, + .createNewDrawable = driCreateNewDrawable, + .createNewContext = driCreateNewContext, + .getAPIMask = driGetAPIMask, + .createNewContextForAPI = driCreateNewContextForAPI, .allocateBuffer = dri2AllocateBuffer, .releaseBuffer = dri2ReleaseBuffer, - .createContextAttribs = dri2CreateContextAttribs, - .createNewScreen2 = dri2CreateNewScreen2, + .createContextAttribs = driCreateContextAttribs, + .createNewScreen2 = driCreateNewScreen2, }; const __DRIswrastExtension driSWRastExtension = { { __DRI_SWRAST, 4 }, driSWRastCreateNewScreen, - dri2CreateNewDrawable, - dri2CreateNewContextForAPI, - dri2CreateContextAttribs, + driCreateNewDrawable, + driCreateNewContextForAPI, + driCreateContextAttribs, driSWRastCreateNewScreen2, }; @@ -792,3 +799,76 @@ driUpdateFramebufferSize(struct gl_context *ctx, const __DRIdrawable *dPriv) assert(fb->Height == dPriv->h); } } + +uint32_t +driGLFormatToImageFormat(gl_format format) +{ + switch (format) { + case MESA_FORMAT_RGB565: + return __DRI_IMAGE_FORMAT_RGB565; + case MESA_FORMAT_XRGB8888: + return __DRI_IMAGE_FORMAT_XRGB8888; + case MESA_FORMAT_ARGB2101010: + return __DRI_IMAGE_FORMAT_ARGB2101010; + case MESA_FORMAT_XRGB2101010_UNORM: + return __DRI_IMAGE_FORMAT_XRGB2101010; + case MESA_FORMAT_ARGB8888: + return __DRI_IMAGE_FORMAT_ARGB8888; + case MESA_FORMAT_RGBA8888_REV: + return __DRI_IMAGE_FORMAT_ABGR8888; + case MESA_FORMAT_RGBX8888_REV: + return __DRI_IMAGE_FORMAT_XBGR8888; + case MESA_FORMAT_R8: + return __DRI_IMAGE_FORMAT_R8; + case MESA_FORMAT_GR88: + return __DRI_IMAGE_FORMAT_GR88; + case MESA_FORMAT_NONE: + return __DRI_IMAGE_FORMAT_NONE; + case MESA_FORMAT_SARGB8: + return __DRI_IMAGE_FORMAT_SARGB8; + default: + return 0; + } +} + +gl_format +driImageFormatToGLFormat(uint32_t image_format) +{ + switch (image_format) { + case __DRI_IMAGE_FORMAT_RGB565: + return MESA_FORMAT_RGB565; + case __DRI_IMAGE_FORMAT_XRGB8888: + return MESA_FORMAT_XRGB8888; + case __DRI_IMAGE_FORMAT_ARGB2101010: + return MESA_FORMAT_ARGB2101010; + case __DRI_IMAGE_FORMAT_XRGB2101010: + return MESA_FORMAT_XRGB2101010_UNORM; + case __DRI_IMAGE_FORMAT_ARGB8888: + return MESA_FORMAT_ARGB8888; + case __DRI_IMAGE_FORMAT_ABGR8888: + return MESA_FORMAT_RGBA8888_REV; + case __DRI_IMAGE_FORMAT_XBGR8888: + return MESA_FORMAT_RGBX8888_REV; + case __DRI_IMAGE_FORMAT_R8: + return MESA_FORMAT_R8; + case __DRI_IMAGE_FORMAT_GR88: + return MESA_FORMAT_GR88; + case __DRI_IMAGE_FORMAT_SARGB8: + return MESA_FORMAT_SARGB8; + case __DRI_IMAGE_FORMAT_NONE: + return MESA_FORMAT_NONE; + default: + return MESA_FORMAT_NONE; + } +} + +/** Image driver interface */ +const __DRIimageDriverExtension driImageDriverExtension = { + .base = { __DRI_IMAGE_DRIVER, __DRI_IMAGE_DRIVER_VERSION }, + + .createNewScreen2 = driCreateNewScreen2, + .createNewDrawable = driCreateNewDrawable, + .createNewContext = driCreateNewContext, + .getAPIMask = driGetAPIMask, + .createContextAttribs = driCreateContextAttribs, +}; diff --git a/mesalib/src/mesa/drivers/dri/common/dri_util.h b/mesalib/src/mesa/drivers/dri/common/dri_util.h index 5b56061e2..79a8564ad 100644 --- a/mesalib/src/mesa/drivers/dri/common/dri_util.h +++ b/mesalib/src/mesa/drivers/dri/common/dri_util.h @@ -57,6 +57,7 @@ #include <GL/internal/dri_interface.h> #include "main/mtypes.h" #include "xmlconfig.h" +#include <stdbool.h> /** * Extensions. @@ -87,6 +88,7 @@ struct __DriverAPIRec { unsigned major_version, unsigned minor_version, uint32_t flags, + bool notify_reset, unsigned *error, void *sharedContextPrivate); @@ -174,6 +176,10 @@ struct __DRIscreenRec { __DRIuseInvalidateExtension *useInvalidate; } dri2; + struct { + __DRIimageLoaderExtension *loader; + } image; + driOptionCache optionInfo; driOptionCache optionCache; @@ -271,10 +277,18 @@ struct __DRIdrawableRec { } dri2; }; +extern uint32_t +driGLFormatToImageFormat(gl_format format); + +extern gl_format +driImageFormatToGLFormat(uint32_t image_format); + extern void dri2InvalidateDrawable(__DRIdrawable *drawable); extern void driUpdateFramebufferSize(struct gl_context *ctx, const __DRIdrawable *dPriv); +extern const __DRIimageDriverExtension driImageDriverExtension; + #endif /* _DRI_UTIL_H_ */ diff --git a/mesalib/src/mesa/drivers/dri/common/utils.c b/mesalib/src/mesa/drivers/dri/common/utils.c index f3780d9b6..b30fca903 100644 --- a/mesalib/src/mesa/drivers/dri/common/utils.c +++ b/mesalib/src/mesa/drivers/dri/common/utils.c @@ -37,6 +37,7 @@ #include "main/cpuinfo.h" #include "main/extensions.h" #include "utils.h" +#include "dri_util.h" unsigned @@ -477,3 +478,66 @@ driIndexConfigAttrib(const __DRIconfig *config, int index, return GL_FALSE; } + +/** + * Implement queries for values that are common across all Mesa drivers + * + * Currently only the following queries are supported by this function: + * + * - \c __DRI2_RENDERER_VERSION + * - \c __DRI2_RENDERER_OPENGL_CORE_PROFILE_VERSION + * - \c __DRI2_RENDERER_OPENGL_COMPATIBLITY_PROFILE_VERSION + * - \c __DRI2_RENDERER_ES_PROFILE_VERSION + * - \c __DRI2_RENDERER_ES2_PROFILE_VERSION + * + * \returns + * Zero if a recognized value of \c param is supplied, -1 otherwise. + */ +int +driQueryRendererIntegerCommon(__DRIscreen *psp, int param, int *value) +{ + switch (param) { + case __DRI2_RENDERER_VERSION: { + static const char *const ver = PACKAGE_VERSION; + char *endptr; + int v[3]; + + v[0] = strtol(ver, &endptr, 10); + assert(endptr[0] == '.'); + if (endptr[0] != '.') + return -1; + + v[1] = strtol(endptr + 1, &endptr, 10); + assert(endptr[0] == '.'); + if (endptr[0] != '.') + return -1; + + v[2] = strtol(endptr + 1, &endptr, 10); + + value[0] = v[0]; + value[1] = v[1]; + value[2] = v[2]; + return 0; + } + case __DRI2_RENDERER_OPENGL_CORE_PROFILE_VERSION: + value[0] = psp->max_gl_core_version / 10; + value[1] = psp->max_gl_core_version % 10; + return 0; + case __DRI2_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION: + value[0] = psp->max_gl_compat_version / 10; + value[1] = psp->max_gl_compat_version % 10; + return 0; + case __DRI2_RENDERER_OPENGL_ES_PROFILE_VERSION: + value[0] = psp->max_gl_es1_version / 10; + value[1] = psp->max_gl_es1_version % 10; + return 0; + case __DRI2_RENDERER_OPENGL_ES2_PROFILE_VERSION: + value[0] = psp->max_gl_es2_version / 10; + value[1] = psp->max_gl_es2_version % 10; + return 0; + default: + break; + } + + return -1; +} diff --git a/mesalib/src/mesa/drivers/dri/common/utils.h b/mesalib/src/mesa/drivers/dri/common/utils.h index e3b3940da..5d6ef879e 100644 --- a/mesalib/src/mesa/drivers/dri/common/utils.h +++ b/mesalib/src/mesa/drivers/dri/common/utils.h @@ -65,4 +65,7 @@ int driIndexConfigAttrib(const __DRIconfig *config, int index, unsigned int *attrib, unsigned int *value); +int +driQueryRendererIntegerCommon(__DRIscreen *psp, int param, int *value); + #endif /* DRI_DEBUG_H */ diff --git a/mesalib/src/mesa/main/api_arrayelt.c b/mesalib/src/mesa/main/api_arrayelt.c index ea0923837..6822465e8 100644 --- a/mesalib/src/mesa/main/api_arrayelt.c +++ b/mesalib/src/mesa/main/api_arrayelt.c @@ -35,6 +35,7 @@ */ #include "glheader.h" +#include "arrayobj.h" #include "api_arrayelt.h" #include "bufferobj.h" #include "context.h" @@ -1485,46 +1486,52 @@ _ae_update_state(struct gl_context *ctx) actx->nr_vbos = 0; + if (arrayObj->NewArrays) { + /* update the derived client arrays */ + _mesa_update_array_object_client_arrays(ctx, arrayObj); + arrayObj->NewArrays = 0; + } + /* conventional vertex arrays */ - if (arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled) { - aa->array = &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX]; + if (arrayObj->_VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled) { + aa->array = &arrayObj->_VertexAttrib[VERT_ATTRIB_COLOR_INDEX]; aa->offset = IndexFuncs[TYPE_IDX(aa->array->Type)]; check_vbo(actx, aa->array->BufferObj); aa++; } - if (arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled) { - aa->array = &arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG]; + if (arrayObj->_VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled) { + aa->array = &arrayObj->_VertexAttrib[VERT_ATTRIB_EDGEFLAG]; aa->offset = _gloffset_EdgeFlagv; check_vbo(actx, aa->array->BufferObj); aa++; } - if (arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL].Enabled) { - aa->array = &arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL]; + if (arrayObj->_VertexAttrib[VERT_ATTRIB_NORMAL].Enabled) { + aa->array = &arrayObj->_VertexAttrib[VERT_ATTRIB_NORMAL]; aa->offset = NormalFuncs[TYPE_IDX(aa->array->Type)]; check_vbo(actx, aa->array->BufferObj); aa++; } - if (arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0].Enabled) { - aa->array = &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0]; + if (arrayObj->_VertexAttrib[VERT_ATTRIB_COLOR0].Enabled) { + aa->array = &arrayObj->_VertexAttrib[VERT_ATTRIB_COLOR0]; aa->offset = ColorFuncs[aa->array->Size-3][TYPE_IDX(aa->array->Type)]; check_vbo(actx, aa->array->BufferObj); aa++; } - if (arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1].Enabled) { - aa->array = &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1]; + if (arrayObj->_VertexAttrib[VERT_ATTRIB_COLOR1].Enabled) { + aa->array = &arrayObj->_VertexAttrib[VERT_ATTRIB_COLOR1]; aa->offset = SecondaryColorFuncs[TYPE_IDX(aa->array->Type)]; check_vbo(actx, aa->array->BufferObj); aa++; } - if (arrayObj->VertexAttrib[VERT_ATTRIB_FOG].Enabled) { - aa->array = &arrayObj->VertexAttrib[VERT_ATTRIB_FOG]; + if (arrayObj->_VertexAttrib[VERT_ATTRIB_FOG].Enabled) { + aa->array = &arrayObj->_VertexAttrib[VERT_ATTRIB_FOG]; aa->offset = FogCoordFuncs[TYPE_IDX(aa->array->Type)]; check_vbo(actx, aa->array->BufferObj); aa++; } for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) { struct gl_client_array *attribArray = - &arrayObj->VertexAttrib[VERT_ATTRIB_TEX(i)]; + &arrayObj->_VertexAttrib[VERT_ATTRIB_TEX(i)]; if (attribArray->Enabled) { /* NOTE: we use generic glVertexAttribNV functions here. * If we ever remove GL_NV_vertex_program this will have to change. @@ -1543,7 +1550,7 @@ _ae_update_state(struct gl_context *ctx) /* generic vertex attribute arrays */ for (i = 1; i < VERT_ATTRIB_GENERIC_MAX; i++) { /* skip zero! */ struct gl_client_array *attribArray = - &arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(i)]; + &arrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC(i)]; if (attribArray->Enabled) { GLint intOrNorm; at->array = attribArray; @@ -1570,18 +1577,18 @@ _ae_update_state(struct gl_context *ctx) } /* finally, vertex position */ - if (arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled) { + if (arrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled) { /* Use glVertex(v) instead of glVertexAttrib(0, v) to be sure it's * issued as the last (provoking) attribute). */ - aa->array = &arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC0]; + aa->array = &arrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC0]; assert(aa->array->Size >= 2); /* XXX fix someday? */ aa->offset = VertexFuncs[aa->array->Size-2][TYPE_IDX(aa->array->Type)]; check_vbo(actx, aa->array->BufferObj); aa++; } - else if (arrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled) { - aa->array = &arrayObj->VertexAttrib[VERT_ATTRIB_POS]; + else if (arrayObj->_VertexAttrib[VERT_ATTRIB_POS].Enabled) { + aa->array = &arrayObj->_VertexAttrib[VERT_ATTRIB_POS]; aa->offset = VertexFuncs[aa->array->Size-2][TYPE_IDX(aa->array->Type)]; check_vbo(actx, aa->array->BufferObj); aa++; diff --git a/mesalib/src/mesa/main/arrayobj.c b/mesalib/src/mesa/main/arrayobj.c index 5d50d29f8..dbf8fdc73 100644 --- a/mesalib/src/mesa/main/arrayobj.c +++ b/mesalib/src/mesa/main/arrayobj.c @@ -72,7 +72,7 @@ _mesa_lookup_arrayobj(struct gl_context *ctx, GLuint id) /** - * For all the vertex arrays in the array object, unbind any pointers + * For all the vertex binding points in the array object, unbind any pointers * to any buffer objects (VBOs). * This is done just prior to array object destruction. */ @@ -81,8 +81,11 @@ unbind_array_object_vbos(struct gl_context *ctx, struct gl_array_object *obj) { GLuint i; - for (i = 0; i < Elements(obj->VertexAttrib); i++) - _mesa_reference_buffer_object(ctx, &obj->VertexAttrib[i].BufferObj, NULL); + for (i = 0; i < Elements(obj->VertexBinding); i++) + _mesa_reference_buffer_object(ctx, &obj->VertexBinding[i].BufferObj, NULL); + + for (i = 0; i < Elements(obj->_VertexAttrib); i++) + _mesa_reference_buffer_object(ctx, &obj->_VertexAttrib[i].BufferObj, NULL); } @@ -181,20 +184,30 @@ _mesa_reference_array_object_(struct gl_context *ctx, static void init_array(struct gl_context *ctx, - struct gl_client_array *array, GLint size, GLint type) + struct gl_array_object *obj, GLuint index, GLint size, GLint type) { + struct gl_vertex_attrib_array *array = &obj->VertexAttrib[index]; + struct gl_vertex_buffer_binding *binding = &obj->VertexBinding[index]; + array->Size = size; array->Type = type; array->Format = GL_RGBA; /* only significant for GL_EXT_vertex_array_bgra */ array->Stride = 0; - array->StrideB = 0; array->Ptr = NULL; + array->RelativeOffset = 0; array->Enabled = GL_FALSE; array->Normalized = GL_FALSE; array->Integer = GL_FALSE; array->_ElementSize = size * _mesa_sizeof_type(type); + array->VertexBinding = index; + + binding->Offset = 0; + binding->Stride = array->_ElementSize; + binding->BufferObj = NULL; + binding->_BoundArrays = BITFIELD64_BIT(index); + /* Vertex array buffers */ - _mesa_reference_buffer_object(ctx, &array->BufferObj, + _mesa_reference_buffer_object(ctx, &binding->BufferObj, ctx->Shared->NullBufferObj); } @@ -215,31 +228,31 @@ _mesa_initialize_array_object( struct gl_context *ctx, obj->RefCount = 1; /* Init the individual arrays */ - for (i = 0; i < Elements(obj->VertexAttrib); i++) { + for (i = 0; i < Elements(obj->_VertexAttrib); i++) { switch (i) { case VERT_ATTRIB_WEIGHT: - init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_WEIGHT], 1, GL_FLOAT); + init_array(ctx, obj, VERT_ATTRIB_WEIGHT, 1, GL_FLOAT); break; case VERT_ATTRIB_NORMAL: - init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_NORMAL], 3, GL_FLOAT); + init_array(ctx, obj, VERT_ATTRIB_NORMAL, 3, GL_FLOAT); break; case VERT_ATTRIB_COLOR1: - init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_COLOR1], 3, GL_FLOAT); + init_array(ctx, obj, VERT_ATTRIB_COLOR1, 3, GL_FLOAT); break; case VERT_ATTRIB_FOG: - init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_FOG], 1, GL_FLOAT); + init_array(ctx, obj, VERT_ATTRIB_FOG, 1, GL_FLOAT); break; case VERT_ATTRIB_COLOR_INDEX: - init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX], 1, GL_FLOAT); + init_array(ctx, obj, VERT_ATTRIB_COLOR_INDEX, 1, GL_FLOAT); break; case VERT_ATTRIB_EDGEFLAG: - init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_EDGEFLAG], 1, GL_BOOL); + init_array(ctx, obj, VERT_ATTRIB_EDGEFLAG, 1, GL_BOOL); break; case VERT_ATTRIB_POINT_SIZE: - init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_POINT_SIZE], 1, GL_FLOAT); + init_array(ctx, obj, VERT_ATTRIB_POINT_SIZE, 1, GL_FLOAT); break; default: - init_array(ctx, &obj->VertexAttrib[i], 4, GL_FLOAT); + init_array(ctx, obj, i, 4, GL_FLOAT); break; } } @@ -279,7 +292,7 @@ remove_array_object( struct gl_context *ctx, struct gl_array_object *obj ) /** * Helper for _mesa_update_array_object_max_element(). - * \return min(arrayObj->VertexAttrib[*]._MaxElement). + * \return min(arrayObj->_VertexAttrib[*]._MaxElement). */ static GLuint compute_max_element(struct gl_array_object *arrayObj, GLbitfield64 enabled) @@ -291,7 +304,7 @@ compute_max_element(struct gl_array_object *arrayObj, GLbitfield64 enabled) GLint attrib = ffsll(enabled) - 1; enabled ^= BITFIELD64_BIT(attrib); - client_array = &arrayObj->VertexAttrib[attrib]; + client_array = &arrayObj->_VertexAttrib[attrib]; assert(client_array->Enabled); _mesa_update_array_max_element(client_array); min = MIN2(min, client_array->_MaxElement); @@ -322,6 +335,32 @@ _mesa_update_array_object_max_element(struct gl_context *ctx, } +/** + * Updates the derived gl_client_arrays when a gl_vertex_attrib_array + * or a gl_vertex_buffer_binding has changed. + */ +void +_mesa_update_array_object_client_arrays(struct gl_context *ctx, struct gl_array_object *arrayObj) +{ + GLbitfield64 arrays = arrayObj->NewArrays; + + while (arrays) { + struct gl_client_array *client_array; + struct gl_vertex_attrib_array *attrib_array; + struct gl_vertex_buffer_binding *buffer_binding; + + GLint attrib = ffsll(arrays) - 1; + arrays ^= BITFIELD64_BIT(attrib); + + attrib_array = &arrayObj->VertexAttrib[attrib]; + buffer_binding = &arrayObj->VertexBinding[attrib_array->VertexBinding]; + client_array = &arrayObj->_VertexAttrib[attrib]; + + _mesa_update_client_array(ctx, client_array, attrib_array, buffer_binding); + } +} + + /**********************************************************************/ /* API Functions */ /**********************************************************************/ diff --git a/mesalib/src/mesa/main/arrayobj.h b/mesalib/src/mesa/main/arrayobj.h index 492ef3501..7c3720242 100644 --- a/mesalib/src/mesa/main/arrayobj.h +++ b/mesalib/src/mesa/main/arrayobj.h @@ -78,6 +78,11 @@ extern void _mesa_update_array_object_max_element(struct gl_context *ctx, struct gl_array_object *arrayObj); +extern void +_mesa_update_array_object_client_arrays(struct gl_context *ctx, + struct gl_array_object *arrayObj); + + /** Returns the bitmask of all enabled arrays in fixed function mode. * * In fixed function mode only the traditional fixed function arrays diff --git a/mesalib/src/mesa/main/attrib.c b/mesalib/src/mesa/main/attrib.c index ca617f744..c9332bd52 100644 --- a/mesalib/src/mesa/main/attrib.c +++ b/mesalib/src/mesa/main/attrib.c @@ -1369,8 +1369,11 @@ copy_array_object(struct gl_context *ctx, /* In theory must be the same anyway, but on recreate make sure it matches */ dest->ARBsemantics = src->ARBsemantics; - for (i = 0; i < Elements(src->VertexAttrib); i++) - _mesa_copy_client_array(ctx, &dest->VertexAttrib[i], &src->VertexAttrib[i]); + for (i = 0; i < Elements(src->_VertexAttrib); i++) { + _mesa_copy_client_array(ctx, &dest->_VertexAttrib[i], &src->_VertexAttrib[i]); + _mesa_copy_vertex_attrib_array(ctx, &dest->VertexAttrib[i], &src->VertexAttrib[i]); + _mesa_copy_vertex_buffer_binding(ctx, &dest->VertexBinding[i], &src->VertexBinding[i]); + } /* _Enabled must be the same than on push */ dest->_Enabled = src->_Enabled; diff --git a/mesalib/src/mesa/main/bufferobj.c b/mesalib/src/mesa/main/bufferobj.c index 1f5506157..b27f592e8 100644 --- a/mesalib/src/mesa/main/bufferobj.c +++ b/mesalib/src/mesa/main/bufferobj.c @@ -655,16 +655,17 @@ _mesa_free_buffer_objects( struct gl_context *ctx ) } } -static bool -handle_bind_buffer_gen(struct gl_context *ctx, - GLenum target, - GLuint buffer, - struct gl_buffer_object **buf_handle) +bool +_mesa_handle_bind_buffer_gen(struct gl_context *ctx, + GLenum target, + GLuint buffer, + struct gl_buffer_object **buf_handle, + const char *caller) { struct gl_buffer_object *buf = *buf_handle; if (!buf && ctx->API == API_OPENGL_CORE) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBindBuffer(non-gen name)"); + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", caller); return false; } @@ -675,7 +676,7 @@ handle_bind_buffer_gen(struct gl_context *ctx, ASSERT(ctx->Driver.NewBufferObject); buf = ctx->Driver.NewBufferObject(ctx, buffer, target); if (!buf) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB"); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller); return false; } _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, buf); @@ -719,7 +720,8 @@ bind_buffer_object(struct gl_context *ctx, GLenum target, GLuint buffer) else { /* non-default buffer object */ newBufObj = _mesa_lookup_bufferobj(ctx, buffer); - if (!handle_bind_buffer_gen(ctx, target, buffer, &newBufObj)) + if (!_mesa_handle_bind_buffer_gen(ctx, target, buffer, + &newBufObj, "glBindBuffer")) return; } @@ -862,8 +864,8 @@ _mesa_DeleteBuffers(GLsizei n, const GLuint *ids) } /* unbind any vertex pointers bound to this buffer */ - for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) { - unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj); + for (j = 0; j < Elements(arrayObj->VertexBinding); j++) { + unbind(ctx, &arrayObj->VertexBinding[j].BufferObj, bufObj); } if (ctx->Array.ArrayBufferObj == bufObj) { @@ -2181,7 +2183,8 @@ _mesa_BindBufferRange(GLenum target, GLuint index, } else { bufObj = _mesa_lookup_bufferobj(ctx, buffer); } - if (!handle_bind_buffer_gen(ctx, target, buffer, &bufObj)) + if (!_mesa_handle_bind_buffer_gen(ctx, target, buffer, + &bufObj, "glBindBufferRange")) return; if (!bufObj) { @@ -2227,7 +2230,8 @@ _mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer) } else { bufObj = _mesa_lookup_bufferobj(ctx, buffer); } - if (!handle_bind_buffer_gen(ctx, target, buffer, &bufObj)) + if (!_mesa_handle_bind_buffer_gen(ctx, target, buffer, + &bufObj, "glBindBufferBase")) return; if (!bufObj) { diff --git a/mesalib/src/mesa/main/bufferobj.h b/mesalib/src/mesa/main/bufferobj.h index 9b582f8c1..0b898a21b 100644 --- a/mesalib/src/mesa/main/bufferobj.h +++ b/mesalib/src/mesa/main/bufferobj.h @@ -28,7 +28,7 @@ #ifndef BUFFEROBJ_H #define BUFFEROBJ_H - +#include <stdbool.h> #include "mtypes.h" @@ -62,6 +62,13 @@ _mesa_init_buffer_objects( struct gl_context *ctx ); extern void _mesa_free_buffer_objects( struct gl_context *ctx ); +extern bool +_mesa_handle_bind_buffer_gen(struct gl_context *ctx, + GLenum target, + GLuint buffer, + struct gl_buffer_object **buf_handle, + const char *caller); + extern void _mesa_update_default_objects_buffer_objects(struct gl_context *ctx); diff --git a/mesalib/src/mesa/main/context.c b/mesalib/src/mesa/main/context.c index 6cdeed19b..d005d2370 100644 --- a/mesalib/src/mesa/main/context.c +++ b/mesalib/src/mesa/main/context.c @@ -678,6 +678,10 @@ _mesa_init_constants(struct gl_context *ctx) ctx->Const.MaxAtomicBufferSize = MAX_ATOMIC_COUNTERS * ATOMIC_COUNTER_SIZE; ctx->Const.MaxCombinedAtomicBuffers = MAX_COMBINED_ATOMIC_BUFFERS; ctx->Const.MaxCombinedAtomicCounters = MAX_ATOMIC_COUNTERS; + + /* GL_ARB_vertex_attrib_binding */ + ctx->Const.MaxVertexAttribRelativeOffset = 2047; + ctx->Const.MaxVertexAttribBindings = MAX_VERTEX_GENERIC_ATTRIBS; } @@ -804,7 +808,7 @@ init_attrib_groups(struct gl_context *ctx) ctx->NewState = _NEW_ALL; ctx->NewDriverState = ~0; ctx->ErrorValue = GL_NO_ERROR; - ctx->ResetStatus = GL_NO_ERROR; + ctx->ShareGroupReset = false; ctx->varying_vp_inputs = VERT_BIT_ALL; return GL_TRUE; diff --git a/mesalib/src/mesa/main/dd.h b/mesalib/src/mesa/main/dd.h index d7c432713..b5b874f47 100644 --- a/mesalib/src/mesa/main/dd.h +++ b/mesalib/src/mesa/main/dd.h @@ -890,6 +890,15 @@ struct dd_function_table { struct gl_texture_object *texObj, struct gl_texture_image *texImage, const GLvoid *vdpSurface, GLuint index); + + /** + * Query reset status for GL_ARB_robustness + * + * Per \c glGetGraphicsResetStatusARB, this function should return a + * non-zero value once after a reset. If a reset is non-atomic, the + * non-zero status should be returned for the duration of the reset. + */ + GLenum (*GetGraphicsResetStatus)(struct gl_context *ctx); }; diff --git a/mesalib/src/mesa/main/enable.c b/mesalib/src/mesa/main/enable.c index dd6a772f9..c047f5df2 100644 --- a/mesalib/src/mesa/main/enable.c +++ b/mesalib/src/mesa/main/enable.c @@ -135,6 +135,8 @@ client_state(struct gl_context *ctx, GLenum cap, GLboolean state) else arrayObj->_Enabled &= ~flag; + arrayObj->NewArrays |= flag; + if (ctx->Driver.Enable) { ctx->Driver.Enable( ctx, cap, state ); } diff --git a/mesalib/src/mesa/main/extensions.c b/mesalib/src/mesa/main/extensions.c index 48c4e9f1b..104618c23 100644 --- a/mesalib/src/mesa/main/extensions.c +++ b/mesalib/src/mesa/main/extensions.c @@ -165,9 +165,11 @@ static const struct extension extension_table[] = { { "GL_ARB_uniform_buffer_object", o(ARB_uniform_buffer_object), GL, 2009 }, { "GL_ARB_vertex_array_bgra", o(EXT_vertex_array_bgra), GL, 2008 }, { "GL_ARB_vertex_array_object", o(dummy_true), GL, 2006 }, + { "GL_ARB_vertex_attrib_binding", o(dummy_true), GL, 2012 }, { "GL_ARB_vertex_buffer_object", o(dummy_true), GLL, 2003 }, { "GL_ARB_vertex_program", o(ARB_vertex_program), GLL, 2002 }, { "GL_ARB_vertex_shader", o(ARB_vertex_shader), GL, 2002 }, + { "GL_ARB_vertex_type_10f_11f_11f_rev", o(ARB_vertex_type_10f_11f_11f_rev), GL, 2013 }, { "GL_ARB_vertex_type_2_10_10_10_rev", o(ARB_vertex_type_2_10_10_10_rev), GL, 2009 }, { "GL_ARB_window_pos", o(dummy_true), GLL, 2001 }, /* EXT extensions */ diff --git a/mesalib/src/mesa/main/get.c b/mesalib/src/mesa/main/get.c index 6a0de0c16..eee855007 100644 --- a/mesalib/src/mesa/main/get.c +++ b/mesalib/src/mesa/main/get.c @@ -550,7 +550,7 @@ static void find_custom_value(struct gl_context *ctx, const struct value_desc *d, union value *v) { struct gl_buffer_object **buffer_obj; - struct gl_client_array *array; + struct gl_vertex_attrib_array *array; GLuint unit, *p; switch (d->pname) { @@ -775,7 +775,7 @@ find_custom_value(struct gl_context *ctx, const struct value_desc *d, union valu break; case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB: v->value_int = - ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_TEX(ctx->Array.ActiveTexture)].BufferObj->Name; + ctx->Array.ArrayObj->VertexBinding[VERT_ATTRIB_TEX(ctx->Array.ActiveTexture)].BufferObj->Name; break; case GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB: v->value_int = ctx->Array.ArrayObj->ElementArrayBufferObj->Name; @@ -819,7 +819,7 @@ find_custom_value(struct gl_context *ctx, const struct value_desc *d, union valu ctx->CurrentRenderbuffer ? ctx->CurrentRenderbuffer->Name : 0; break; case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES: - v->value_int = ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POINT_SIZE].BufferObj->Name; + v->value_int = ctx->Array.ArrayObj->VertexBinding[VERT_ATTRIB_POINT_SIZE].BufferObj->Name; break; case GL_FOG_COLOR: @@ -1740,6 +1740,30 @@ find_value_indexed(const char *func, GLenum pname, GLuint index, union value *v) goto invalid_value; v->value_int64 = ctx->AtomicBufferBindings[index].Size; return TYPE_INT64; + + case GL_VERTEX_BINDING_DIVISOR: + if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_instanced_arrays) + goto invalid_enum; + if (index >= ctx->Const.VertexProgram.MaxAttribs) + goto invalid_value; + v->value_int = ctx->Array.ArrayObj->VertexBinding[VERT_ATTRIB_GENERIC(index)].InstanceDivisor; + return TYPE_INT; + + case GL_VERTEX_BINDING_OFFSET: + if (!_mesa_is_desktop_gl(ctx)) + goto invalid_enum; + if (index >= ctx->Const.VertexProgram.MaxAttribs) + goto invalid_value; + v->value_int = ctx->Array.ArrayObj->VertexBinding[VERT_ATTRIB_GENERIC(index)].Offset; + return TYPE_INT; + + case GL_VERTEX_BINDING_STRIDE: + if (!_mesa_is_desktop_gl(ctx)) + goto invalid_enum; + if (index >= ctx->Const.VertexProgram.MaxAttribs) + goto invalid_value; + v->value_int = ctx->Array.ArrayObj->VertexBinding[VERT_ATTRIB_GENERIC(index)].Stride; + return TYPE_INT; } invalid_enum: diff --git a/mesalib/src/mesa/main/get_hash_params.py b/mesalib/src/mesa/main/get_hash_params.py index 0851b7b70..c961feeee 100644 --- a/mesalib/src/mesa/main/get_hash_params.py +++ b/mesalib/src/mesa/main/get_hash_params.py @@ -221,9 +221,9 @@ descriptor=[ [ "SAMPLE_ALPHA_TO_ONE_ARB", "CONTEXT_BOOL(Multisample.SampleAlphaToOne), NO_EXTRA" ], # GL_ARB_vertex_buffer_object - [ "VERTEX_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexAttrib[VERT_ATTRIB_POS].BufferObj), NO_EXTRA" ], - [ "NORMAL_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexAttrib[VERT_ATTRIB_NORMAL].BufferObj), NO_EXTRA" ], - [ "COLOR_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexAttrib[VERT_ATTRIB_COLOR0].BufferObj), NO_EXTRA" ], + [ "VERTEX_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexBinding[VERT_ATTRIB_POS].BufferObj), NO_EXTRA" ], + [ "NORMAL_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexBinding[VERT_ATTRIB_NORMAL].BufferObj), NO_EXTRA" ], + [ "COLOR_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexBinding[VERT_ATTRIB_COLOR0].BufferObj), NO_EXTRA" ], [ "TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA" ], # GL_OES_point_sprite @@ -585,10 +585,10 @@ descriptor=[ [ "PRIMITIVE_RESTART_INDEX_NV", "CONTEXT_INT(Array.RestartIndex), extra_NV_primitive_restart" ], # GL_ARB_vertex_buffer_object - [ "INDEX_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexAttrib[VERT_ATTRIB_COLOR_INDEX].BufferObj), NO_EXTRA" ], - [ "EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexAttrib[VERT_ATTRIB_EDGEFLAG].BufferObj), NO_EXTRA" ], - [ "SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexAttrib[VERT_ATTRIB_COLOR1].BufferObj), NO_EXTRA" ], - [ "FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexAttrib[VERT_ATTRIB_FOG].BufferObj), NO_EXTRA" ], + [ "INDEX_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexBinding[VERT_ATTRIB_COLOR_INDEX].BufferObj), NO_EXTRA" ], + [ "EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexBinding[VERT_ATTRIB_EDGEFLAG].BufferObj), NO_EXTRA" ], + [ "SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexBinding[VERT_ATTRIB_COLOR1].BufferObj), NO_EXTRA" ], + [ "FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexBinding[VERT_ATTRIB_FOG].BufferObj), NO_EXTRA" ], # GL_ARB_vertex_program # == GL_VERTEX_PROGRAM_NV @@ -737,6 +737,10 @@ descriptor=[ [ "MAX_GEOMETRY_ATOMIC_COUNTERS", "CONTEXT_INT(Const.GeometryProgram.MaxAtomicCounters), extra_ARB_shader_atomic_counters_and_geometry_shader" ], [ "MAX_COMBINED_ATOMIC_COUNTER_BUFFERS", "CONTEXT_INT(Const.MaxCombinedAtomicBuffers), extra_ARB_shader_atomic_counters" ], [ "MAX_COMBINED_ATOMIC_COUNTERS", "CONTEXT_INT(Const.MaxCombinedAtomicCounters), extra_ARB_shader_atomic_counters" ], + +# GL_ARB_vertex_attrib_binding + [ "MAX_VERTEX_ATTRIB_RELATIVE_OFFSET", "CONTEXT_ENUM(Const.MaxVertexAttribRelativeOffset), NO_EXTRA" ], + [ "MAX_VERTEX_ATTRIB_BINDINGS", "CONTEXT_ENUM(Const.MaxVertexAttribBindings), NO_EXTRA" ], ]}, # Enums restricted to OpenGL Core profile diff --git a/mesalib/src/mesa/main/getstring.c b/mesalib/src/mesa/main/getstring.c index 0e075427f..d8189115a 100644 --- a/mesalib/src/mesa/main/getstring.c +++ b/mesalib/src/mesa/main/getstring.c @@ -23,7 +23,7 @@ */ - +#include <stdbool.h> #include "glheader.h" #include "context.h" #include "get.h" @@ -305,11 +305,50 @@ GLenum GLAPIENTRY _mesa_GetGraphicsResetStatusARB( void ) { GET_CURRENT_CONTEXT(ctx); - GLenum status = ctx->ResetStatus; + GLenum status = GL_NO_ERROR; + + /* The ARB_robustness specification says: + * + * "If the reset notification behavior is NO_RESET_NOTIFICATION_ARB, + * then the implementation will never deliver notification of reset + * events, and GetGraphicsResetStatusARB will always return NO_ERROR." + */ + if (ctx->Const.ResetStrategy == GL_NO_RESET_NOTIFICATION_ARB) { + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, + "glGetGraphicsResetStatusARB always returns GL_NO_ERROR " + "because reset notifictation was not requested at context " + "creation.\n"); + + return GL_NO_ERROR; + } - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glGetGraphicsResetStatusARB" - "(always returns GL_NO_ERROR)\n"); + if (ctx->Driver.GetGraphicsResetStatus) { + /* Query the reset status of this context from the driver core. + */ + status = ctx->Driver.GetGraphicsResetStatus(ctx); + + _glthread_LOCK_MUTEX(ctx->Shared->Mutex); + + /* If this context has not been affected by a GPU reset, check to see if + * some other context in the share group has been affected by a reset. + * If another context saw a reset but this context did not, assume that + * this context was not guilty. + */ + if (status != GL_NO_ERROR) { + ctx->Shared->ShareGroupReset = true; + } else if (ctx->Shared->ShareGroupReset && !ctx->ShareGroupReset) { + status = GL_INNOCENT_CONTEXT_RESET_ARB; + } + + ctx->ShareGroupReset = ctx->Shared->ShareGroupReset; + _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); + } + + if (!ctx->Driver.GetGraphicsResetStatus && (MESA_VERBOSE & VERBOSE_API)) + _mesa_debug(ctx, + "glGetGraphicsResetStatusARB always returns GL_NO_ERROR " + "because the driver doesn't track reset status.\n"); return status; } diff --git a/mesalib/src/mesa/main/glformats.c b/mesalib/src/mesa/main/glformats.c index dfee6f196..740faa890 100644 --- a/mesalib/src/mesa/main/glformats.c +++ b/mesalib/src/mesa/main/glformats.c @@ -345,6 +345,11 @@ _mesa_bytes_per_vertex_attrib(GLint comps, GLenum type) return sizeof(GLuint); else return -1; + case GL_UNSIGNED_INT_10F_11F_11F_REV: + if (comps == 3) + return sizeof(GLuint); + else + return -1; default: return -1; } diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h index b5c5583d6..ae96e2326 100644 --- a/mesalib/src/mesa/main/mtypes.h +++ b/mesalib/src/mesa/main/mtypes.h @@ -35,6 +35,7 @@ #include <stdint.h> /* uint32_t */ +#include <stdbool.h> #include "main/glheader.h" #include "main/config.h" @@ -1474,6 +1475,44 @@ struct gl_client_array /** + * Vertex attribute array as seen by the client. + * + * Contains the size, type, format and normalization flag, + * along with the index of a vertex buffer binding point. + * + * Note that the Stride field corresponds to VERTEX_ATTRIB_ARRAY_STRIDE + * and is only present for backwards compatibility reasons. + * Rendering always uses VERTEX_BINDING_STRIDE. + * The gl*Pointer() functions will set VERTEX_ATTRIB_ARRAY_STRIDE + * and VERTEX_BINDING_STRIDE to the same value, while + * glBindVertexBuffer() will only set VERTEX_BINDING_STRIDE. + */ +struct gl_vertex_attrib_array +{ + GLint Size; /**< Components per element (1,2,3,4) */ + GLenum Type; /**< Datatype: GL_FLOAT, GL_INT, etc */ + GLenum Format; /**< Default: GL_RGBA, but may be GL_BGRA */ + GLsizei Stride; /**< Stride as specified with gl*Pointer() */ + const GLubyte *Ptr; /**< Points to client array data. Not used when a VBO is bound */ + GLintptr RelativeOffset; /**< Offset of the first element relative to the binding offset */ + GLboolean Enabled; /**< Whether the array is enabled */ + GLboolean Normalized; /**< Fixed-point values are normalized when converted to floats */ + GLboolean Integer; /**< Fixed-point values are not converted to floats */ + GLuint _ElementSize; /**< Size of each element in bytes */ + GLuint VertexBinding; /**< Vertex buffer binding */ +}; + +struct gl_vertex_buffer_binding +{ + GLintptr Offset; /**< User-specified offset */ + GLsizei Stride; /**< User-specified stride */ + GLuint InstanceDivisor; /**< GL_ARB_instanced_arrays */ + struct gl_buffer_object *BufferObj; /**< GL_ARB_vertex_buffer_object */ + GLbitfield64 _BoundArrays; /**< Arrays bound to this binding point */ +}; + + +/** * Collection of vertex arrays. Defined by the GL_APPLE_vertex_array_object * extension, but a nice encapsulation in any case. */ @@ -1507,12 +1546,21 @@ struct gl_array_object */ GLboolean EverBound; + /** Derived vertex attribute arrays */ + struct gl_client_array _VertexAttrib[VERT_ATTRIB_MAX]; + /** Vertex attribute arrays */ - struct gl_client_array VertexAttrib[VERT_ATTRIB_MAX]; + struct gl_vertex_attrib_array VertexAttrib[VERT_ATTRIB_MAX]; + + /** Vertex buffer bindings */ + struct gl_vertex_buffer_binding VertexBinding[VERT_ATTRIB_MAX]; /** Mask of VERT_BIT_* values indicating which arrays are enabled */ GLbitfield64 _Enabled; + /** Mask of VERT_BIT_* values indicating changed/dirty arrays */ + GLbitfield64 NewArrays; + /** * Min of all enabled arrays' _MaxElement. When arrays reside inside VBOs * we can determine the max legal (in bounds) glDrawElements array index. @@ -2765,6 +2813,17 @@ struct gl_shared_state /** GL_ARB_sampler_objects */ struct _mesa_HashTable *SamplerObjects; + + /** + * Some context in this share group was affected by a GPU reset + * + * On the next call to \c glGetGraphicsResetStatus, contexts that have not + * been affected by a GPU reset must also return + * \c GL_INNOCENT_CONTEXT_RESET_ARB. + * + * Once this field becomes true, it is never reset to false. + */ + bool ShareGroupReset; }; @@ -3213,6 +3272,10 @@ struct gl_constants GLuint MaxAtomicBufferSize; GLuint MaxCombinedAtomicBuffers; GLuint MaxCombinedAtomicCounters; + + /** GL_ARB_vertex_attrib_binding */ + GLint MaxVertexAttribRelativeOffset; + GLint MaxVertexAttribBindings; }; @@ -3291,6 +3354,7 @@ struct gl_extensions GLboolean ARB_uniform_buffer_object; GLboolean ARB_vertex_program; GLboolean ARB_vertex_shader; + GLboolean ARB_vertex_type_10f_11f_11f_rev; GLboolean ARB_vertex_type_2_10_10_10_rev; GLboolean EXT_blend_color; GLboolean EXT_blend_equation_separate; @@ -3851,9 +3915,6 @@ struct gl_context GLenum ErrorValue; /**< Last error code */ - /* GL_ARB_robustness */ - GLenum ResetStatus; - /** * Recognize and silence repeated error debug messages in buggy apps. */ @@ -3918,6 +3979,13 @@ struct gl_context const void *vdpGetProcAddress; struct set *vdpSurfaces; /*@}*/ + + /** + * Has this context observed a GPU reset in any context in the share group? + * + * Once this field becomes true, it is never reset to false. + */ + GLboolean ShareGroupReset; }; diff --git a/mesalib/src/mesa/main/state.c b/mesalib/src/mesa/main/state.c index 23926410b..33070b7e0 100644 --- a/mesalib/src/mesa/main/state.c +++ b/mesalib/src/mesa/main/state.c @@ -410,6 +410,9 @@ _mesa_update_state_locked( struct gl_context *ctx ) new_prog_state |= update_program( ctx ); } + if (new_state & _NEW_ARRAY) + _mesa_update_array_object_client_arrays(ctx, ctx->Array.ArrayObj); + if (ctx->Const.CheckArrayBounds && new_state & (_NEW_ARRAY | _NEW_PROGRAM | _NEW_BUFFER_OBJECT)) { _mesa_update_array_object_max_element(ctx, ctx->Array.ArrayObj); @@ -430,6 +433,7 @@ _mesa_update_state_locked( struct gl_context *ctx ) new_state = ctx->NewState | new_prog_state; ctx->NewState = 0; ctx->Driver.UpdateState(ctx, new_state); + ctx->Array.ArrayObj->NewArrays = 0x0; } diff --git a/mesalib/src/mesa/main/streaming-load-memcpy.c b/mesalib/src/mesa/main/streaming-load-memcpy.c new file mode 100644 index 000000000..d7147afdc --- /dev/null +++ b/mesalib/src/mesa/main/streaming-load-memcpy.c @@ -0,0 +1,85 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt <eric@anholt.net> + * Matt Turner <mattst88@gmail.com> + * + */ + +#include "main/macros.h" +#include "main/streaming-load-memcpy.h" +#include <smmintrin.h> + +/* Copies memory from src to dst, using SSE 4.1's MOVNTDQA to get streaming + * read performance from uncached memory. + */ +void +_mesa_streaming_load_memcpy(void *restrict dst, void *restrict src, size_t len) +{ + char *restrict d = dst; + char *restrict s = src; + + /* If dst and src are not co-aligned, fallback to memcpy(). */ + if (((uintptr_t)d & 15) != ((uintptr_t)s & 15)) { + memcpy(d, s, len); + return; + } + + /* memcpy() the misaligned header. At the end of this if block, <d> and <s> + * are aligned to a 16-byte boundary or <len> == 0. + */ + if ((uintptr_t)d & 15) { + uintptr_t bytes_before_alignment_boundary = 16 - ((uintptr_t)d & 15); + assert(bytes_before_alignment_boundary < 16); + + memcpy(d, s, MIN2(bytes_before_alignment_boundary, len)); + + d = (char *)ALIGN((uintptr_t)d, 16); + s = (char *)ALIGN((uintptr_t)s, 16); + len -= MIN2(bytes_before_alignment_boundary, len); + } + + while (len >= 64) { + __m128i *dst_cacheline = (__m128i *)d; + __m128i *src_cacheline = (__m128i *)s; + + __m128i temp1 = _mm_stream_load_si128(src_cacheline + 0); + __m128i temp2 = _mm_stream_load_si128(src_cacheline + 1); + __m128i temp3 = _mm_stream_load_si128(src_cacheline + 2); + __m128i temp4 = _mm_stream_load_si128(src_cacheline + 3); + + _mm_store_si128(dst_cacheline + 0, temp1); + _mm_store_si128(dst_cacheline + 1, temp2); + _mm_store_si128(dst_cacheline + 2, temp3); + _mm_store_si128(dst_cacheline + 3, temp4); + + d += 64; + s += 64; + len -= 64; + } + + /* memcpy() the tail. */ + if (len) { + memcpy(d, s, len); + } +} diff --git a/mesalib/src/mesa/main/streaming-load-memcpy.h b/mesalib/src/mesa/main/streaming-load-memcpy.h new file mode 100644 index 000000000..41eeeeca0 --- /dev/null +++ b/mesalib/src/mesa/main/streaming-load-memcpy.h @@ -0,0 +1,33 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt <eric@anholt.net> + * Matt Turner <mattst88@gmail.com> + * + */ + +/* Copies memory from src to dst, using SSE 4.1's MOVNTDQA to get streaming + * read performance from uncached memory. + */ +void +_mesa_streaming_load_memcpy(void *restrict dst, void *restrict src, size_t len); diff --git a/mesalib/src/mesa/main/varray.c b/mesalib/src/mesa/main/varray.c index dee476abb..d17d698d3 100644 --- a/mesalib/src/mesa/main/varray.c +++ b/mesalib/src/mesa/main/varray.c @@ -60,6 +60,7 @@ #define FIXED_GL_BIT 0x800 #define UNSIGNED_INT_2_10_10_10_REV_BIT 0x1000 #define INT_2_10_10_10_REV_BIT 0x2000 +#define UNSIGNED_INT_10F_11F_11F_REV_BIT 0x4000 /** Convert GL datatype enum into a <type>_BIT value seen above */ @@ -96,6 +97,8 @@ type_to_bit(const struct gl_context *ctx, GLenum type) return UNSIGNED_INT_2_10_10_10_REV_BIT; case GL_INT_2_10_10_10_REV: return INT_2_10_10_10_REV_BIT; + case GL_UNSIGNED_INT_10F_11F_11F_REV: + return UNSIGNED_INT_10F_11F_11F_REV_BIT; default: return 0; } @@ -103,54 +106,110 @@ type_to_bit(const struct gl_context *ctx, GLenum type) /** - * Do error checking and update state for glVertex/Color/TexCoord/...Pointer - * functions. - * - * \param func name of calling function used for error reporting - * \param attrib the attribute array index to update - * \param legalTypes bitmask of *_BIT above indicating legal datatypes - * \param sizeMin min allowable size value - * \param sizeMax max allowable size value (may also be BGRA_OR_4) - * \param size components per element (1, 2, 3 or 4) - * \param type datatype of each component (GL_FLOAT, GL_INT, etc) - * \param stride stride between elements, in elements - * \param normalized are integer types converted to floats in [-1, 1]? - * \param integer integer-valued values (will not be normalized to [-1,1]) - * \param ptr the address (or offset inside VBO) of the array data + * Sets the VertexBinding field in the vertex attribute given by attribIndex. */ static void -update_array(struct gl_context *ctx, - const char *func, - GLuint attrib, GLbitfield legalTypesMask, - GLint sizeMin, GLint sizeMax, - GLint size, GLenum type, GLsizei stride, - GLboolean normalized, GLboolean integer, - const GLvoid *ptr) +vertex_attrib_binding(struct gl_context *ctx, GLuint attribIndex, + GLuint bindingIndex) { - struct gl_client_array *array; - GLbitfield typeBit; - GLsizei elementSize; - GLenum format = GL_RGBA; + struct gl_array_object *arrayObj = ctx->Array.ArrayObj; + struct gl_vertex_attrib_array *array = &arrayObj->VertexAttrib[attribIndex]; - /* Page 407 (page 423 of the PDF) of the OpenGL 3.0 spec says: - * - * "Client vertex arrays - all vertex array attribute pointers must - * refer to buffer objects (section 2.9.2). The default vertex array - * object (the name zero) is also deprecated. Calling - * VertexAttribPointer when no buffer object or no vertex array object - * is bound will generate an INVALID_OPERATION error..." - * - * The check for VBOs is handled below. - */ - if (ctx->API == API_OPENGL_CORE - && (ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no array object bound)", - func); - return; + if (array->VertexBinding != bindingIndex) { + const GLbitfield64 array_bit = VERT_BIT(attribIndex); + + FLUSH_VERTICES(ctx, _NEW_ARRAY); + + arrayObj->VertexBinding[array->VertexBinding]._BoundArrays &= ~array_bit; + arrayObj->VertexBinding[bindingIndex]._BoundArrays |= array_bit; + + array->VertexBinding = bindingIndex; + + arrayObj->NewArrays |= array_bit; } +} + + +/** + * Binds a buffer object to the vertex buffer binding point given by index, + * and sets the Offset and Stride fields. + */ +static void +bind_vertex_buffer(struct gl_context *ctx, GLuint index, + struct gl_buffer_object *vbo, + GLintptr offset, GLsizei stride) +{ + struct gl_array_object *arrayObj = ctx->Array.ArrayObj; + struct gl_vertex_buffer_binding *binding = &arrayObj->VertexBinding[index]; + + if (binding->BufferObj != vbo || + binding->Offset != offset || + binding->Stride != stride) { + + FLUSH_VERTICES(ctx, _NEW_ARRAY); + + _mesa_reference_buffer_object(ctx, &binding->BufferObj, vbo); + + binding->Offset = offset; + binding->Stride = stride; + + arrayObj->NewArrays |= binding->_BoundArrays; + } +} + + +/** + * Sets the InstanceDivisor field in the vertex buffer binding point + * given by bindingIndex. + */ +static void +vertex_binding_divisor(struct gl_context *ctx, GLuint bindingIndex, + GLuint divisor) +{ + struct gl_array_object *arrayObj = ctx->Array.ArrayObj; + struct gl_vertex_buffer_binding *binding = + &arrayObj->VertexBinding[bindingIndex]; + + if (binding->InstanceDivisor != divisor) { + FLUSH_VERTICES(ctx, _NEW_ARRAY); + binding->InstanceDivisor = divisor; + arrayObj->NewArrays |= binding->_BoundArrays; + } +} + + +/** + * Does error checking and updates the format in an attrib array. + * + * Called by update_array() and VertexAttrib*Format(). + * + * \param func Name of calling function used for error reporting + * \param attrib The index of the attribute array + * \param legalTypes Bitmask of *_BIT above indicating legal datatypes + * \param sizeMin Min allowable size value + * \param sizeMax Max allowable size value (may also be BGRA_OR_4) + * \param size Components per element (1, 2, 3 or 4) + * \param type Datatype of each component (GL_FLOAT, GL_INT, etc) + * \param normalized Whether integer types are converted to floats in [-1, 1] + * \param integer Integer-valued values (will not be normalized to [-1, 1]) + * \param relativeOffset Offset of the first element relative to the binding offset. + */ +static bool +update_array_format(struct gl_context *ctx, + const char *func, + GLuint attrib, GLbitfield legalTypesMask, + GLint sizeMin, GLint sizeMax, + GLint size, GLenum type, + GLboolean normalized, GLboolean integer, + GLuint relativeOffset) +{ + struct gl_vertex_attrib_array *array; + GLbitfield typeBit; + GLuint elementSize; + GLenum format = GL_RGBA; if (_mesa_is_gles(ctx)) { - legalTypesMask &= ~(FIXED_GL_BIT | DOUBLE_BIT); + legalTypesMask &= ~(FIXED_GL_BIT | DOUBLE_BIT | UNSIGNED_INT_10F_11F_11F_REV_BIT); /* GL_INT and GL_UNSIGNED_INT data is not allowed in OpenGL ES until * 3.0. The 2_10_10_10 types are added in OpenGL ES 3.0 or @@ -180,13 +239,16 @@ update_array(struct gl_context *ctx, if (!ctx->Extensions.ARB_vertex_type_2_10_10_10_rev) legalTypesMask &= ~(UNSIGNED_INT_2_10_10_10_REV_BIT | INT_2_10_10_10_REV_BIT); + + if (!ctx->Extensions.ARB_vertex_type_10f_11f_11f_rev) + legalTypesMask &= ~UNSIGNED_INT_10F_11F_11F_REV_BIT; } typeBit = type_to_bit(ctx, type); if (typeBit == 0x0 || (typeBit & legalTypesMask) == 0x0) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(type = %s)", func, _mesa_lookup_enum_by_nr(type)); - return; + return false; } /* Do size parameter checking. @@ -206,26 +268,26 @@ update_array(struct gl_context *ctx, * ... * • size is BGRA and normalized is FALSE;" */ - GLboolean bgra_error = GL_FALSE; + bool bgra_error = false; if (ctx->Extensions.ARB_vertex_type_2_10_10_10_rev) { if (type != GL_UNSIGNED_INT_2_10_10_10_REV && type != GL_INT_2_10_10_10_REV && type != GL_UNSIGNED_BYTE) - bgra_error = GL_TRUE; + bgra_error = true; } else if (type != GL_UNSIGNED_BYTE) - bgra_error = GL_TRUE; + bgra_error = true; if (bgra_error) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(size=GL_BGRA and type=%s)", func, _mesa_lookup_enum_by_nr(type)); - return; + return false; } if (!normalized) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(size=GL_BGRA and normalized=GL_FALSE)", func); - return; + return false; } format = GL_BGRA; @@ -233,18 +295,106 @@ update_array(struct gl_context *ctx, } else if (size < sizeMin || size > sizeMax || size > 4) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d)", func, size); - return; + return false; } if (ctx->Extensions.ARB_vertex_type_2_10_10_10_rev && (type == GL_UNSIGNED_INT_2_10_10_10_REV || type == GL_INT_2_10_10_10_REV) && size != 4) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(size=%d)", func, size); - return; + return false; + } + + /* The ARB_vertex_attrib_binding_spec says: + * + * An INVALID_VALUE error is generated if <relativeoffset> is larger than + * the value of MAX_VERTEX_ATTRIB_RELATIVE_OFFSET. + */ + if (relativeOffset > ctx->Const.MaxVertexAttribRelativeOffset) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(relativeOffset=%d > " + "GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET)", + func, relativeOffset); + return false; + } + + if (ctx->Extensions.ARB_vertex_type_10f_11f_11f_rev && + type == GL_UNSIGNED_INT_10F_11F_11F_REV && size != 3) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(size=%d)", func, size); + return false; } ASSERT(size <= 4); + elementSize = _mesa_bytes_per_vertex_attrib(size, type); + assert(elementSize != -1); + + array = &ctx->Array.ArrayObj->VertexAttrib[attrib]; + array->Size = size; + array->Type = type; + array->Format = format; + array->Normalized = normalized; + array->Integer = integer; + array->RelativeOffset = relativeOffset; + array->_ElementSize = elementSize; + + ctx->Array.ArrayObj->NewArrays |= VERT_BIT(attrib); + ctx->NewState |= _NEW_ARRAY; + + return true; +} + + +/** + * Do error checking and update state for glVertex/Color/TexCoord/...Pointer + * functions. + * + * \param func name of calling function used for error reporting + * \param attrib the attribute array index to update + * \param legalTypes bitmask of *_BIT above indicating legal datatypes + * \param sizeMin min allowable size value + * \param sizeMax max allowable size value (may also be BGRA_OR_4) + * \param size components per element (1, 2, 3 or 4) + * \param type datatype of each component (GL_FLOAT, GL_INT, etc) + * \param stride stride between elements, in elements + * \param normalized are integer types converted to floats in [-1, 1]? + * \param integer integer-valued values (will not be normalized to [-1,1]) + * \param ptr the address (or offset inside VBO) of the array data + */ +static void +update_array(struct gl_context *ctx, + const char *func, + GLuint attrib, GLbitfield legalTypesMask, + GLint sizeMin, GLint sizeMax, + GLint size, GLenum type, GLsizei stride, + GLboolean normalized, GLboolean integer, + const GLvoid *ptr) +{ + struct gl_vertex_attrib_array *array; + GLsizei effectiveStride; + + /* Page 407 (page 423 of the PDF) of the OpenGL 3.0 spec says: + * + * "Client vertex arrays - all vertex array attribute pointers must + * refer to buffer objects (section 2.9.2). The default vertex array + * object (the name zero) is also deprecated. Calling + * VertexAttribPointer when no buffer object or no vertex array object + * is bound will generate an INVALID_OPERATION error..." + * + * The check for VBOs is handled below. + */ + if (ctx->API == API_OPENGL_CORE + && (ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no array object bound)", + func); + return; + } + + if (!update_array_format(ctx, func, attrib, legalTypesMask, sizeMin, sizeMax, + size, type, normalized, integer, 0)) { + return; + } + if (stride < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "%s(stride=%d)", func, stride ); return; @@ -268,24 +418,18 @@ update_array(struct gl_context *ctx, return; } - elementSize = _mesa_bytes_per_vertex_attrib(size, type); - assert(elementSize != -1); + /* Reset the vertex attrib binding */ + vertex_attrib_binding(ctx, attrib, attrib); + /* The Stride and Ptr fields are not set by update_array_format() */ array = &ctx->Array.ArrayObj->VertexAttrib[attrib]; - array->Size = size; - array->Type = type; - array->Format = format; array->Stride = stride; - array->StrideB = stride ? stride : elementSize; - array->Normalized = normalized; - array->Integer = integer; - array->Ptr = (const GLubyte *) ptr; - array->_ElementSize = elementSize; + array->Ptr = (const GLvoid *) ptr; - _mesa_reference_buffer_object(ctx, &array->BufferObj, - ctx->Array.ArrayBufferObj); - - ctx->NewState |= _NEW_ARRAY; + /* Update the vertex buffer binding */ + effectiveStride = stride != 0 ? stride : array->_ElementSize; + bind_vertex_buffer(ctx, attrib, ctx->Array.ArrayBufferObj, + (GLintptr) ptr, effectiveStride); } @@ -473,7 +617,8 @@ _mesa_VertexAttribPointer(GLuint index, GLint size, GLenum type, HALF_BIT | FLOAT_BIT | DOUBLE_BIT | FIXED_ES_BIT | FIXED_GL_BIT | UNSIGNED_INT_2_10_10_10_REV_BIT | - INT_2_10_10_10_REV_BIT); + INT_2_10_10_10_REV_BIT | + UNSIGNED_INT_10F_11F_11F_REV_BIT); GET_CURRENT_CONTEXT(ctx); if (index >= ctx->Const.VertexProgram.MaxAttribs) { @@ -530,13 +675,14 @@ _mesa_EnableVertexAttribArray(GLuint index) arrayObj = ctx->Array.ArrayObj; - ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(arrayObj->VertexAttrib)); + ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(arrayObj->_VertexAttrib)); if (!arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled) { /* was disabled, now being enabled */ FLUSH_VERTICES(ctx, _NEW_ARRAY); arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled = GL_TRUE; arrayObj->_Enabled |= VERT_BIT_GENERIC(index); + arrayObj->NewArrays |= VERT_BIT_GENERIC(index); } } @@ -555,13 +701,14 @@ _mesa_DisableVertexAttribArray(GLuint index) arrayObj = ctx->Array.ArrayObj; - ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(arrayObj->VertexAttrib)); + ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(arrayObj->_VertexAttrib)); if (arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled) { /* was enabled, now being disabled */ FLUSH_VERTICES(ctx, _NEW_ARRAY); arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled = GL_FALSE; arrayObj->_Enabled &= ~VERT_BIT_GENERIC(index); + arrayObj->NewArrays |= VERT_BIT_GENERIC(index); } } @@ -575,16 +722,17 @@ static GLuint get_vertex_array_attrib(struct gl_context *ctx, GLuint index, GLenum pname, const char *caller) { - const struct gl_client_array *array; + const struct gl_array_object *arrayObj = ctx->Array.ArrayObj; + const struct gl_vertex_attrib_array *array; if (index >= ctx->Const.VertexProgram.MaxAttribs) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%u)", caller, index); return 0; } - ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(ctx->Array.ArrayObj->VertexAttrib)); + ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(arrayObj->VertexAttrib)); - array = &ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)]; + array = &arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)]; switch (pname) { case GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB: @@ -598,7 +746,7 @@ get_vertex_array_attrib(struct gl_context *ctx, GLuint index, GLenum pname, case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB: return array->Normalized; case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB: - return array->BufferObj->Name; + return arrayObj->VertexBinding[array->VertexBinding].BufferObj->Name; case GL_VERTEX_ATTRIB_ARRAY_INTEGER: if ((_mesa_is_desktop_gl(ctx) && (ctx->Version >= 30 || ctx->Extensions.EXT_gpu_shader4)) @@ -609,7 +757,17 @@ get_vertex_array_attrib(struct gl_context *ctx, GLuint index, GLenum pname, case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB: if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_instanced_arrays) || _mesa_is_gles3(ctx)) { - return array->InstanceDivisor; + return arrayObj->VertexBinding[array->VertexBinding].InstanceDivisor; + } + goto error; + case GL_VERTEX_ATTRIB_BINDING: + if (_mesa_is_desktop_gl(ctx)) { + return array->VertexBinding - VERT_ATTRIB_GENERIC0; + } + goto error; + case GL_VERTEX_ATTRIB_RELATIVE_OFFSET: + if (_mesa_is_desktop_gl(ctx)) { + return array->RelativeOffset; } goto error; default: @@ -643,7 +801,7 @@ get_current_attrib(struct gl_context *ctx, GLuint index, const char *function) return NULL; } - ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(ctx->Array.ArrayObj->VertexAttrib)); + ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(ctx->Array.ArrayObj->_VertexAttrib)); FLUSH_CURRENT(ctx, 0); return ctx->Current.Attrib[VERT_ATTRIB_GENERIC(index)]; @@ -765,7 +923,7 @@ _mesa_GetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid **pointer) return; } - ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(ctx->Array.ArrayObj->VertexAttrib)); + ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(ctx->Array.ArrayObj->_VertexAttrib)); *pointer = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Ptr; } @@ -1141,9 +1299,10 @@ _mesa_PrimitiveRestartIndex(GLuint index) void GLAPIENTRY _mesa_VertexAttribDivisor(GLuint index, GLuint divisor) { - struct gl_client_array *array; GET_CURRENT_CONTEXT(ctx); + const GLuint genericIndex = VERT_ATTRIB_GENERIC(index); + if (!ctx->Extensions.ARB_instanced_arrays) { _mesa_error(ctx, GL_INVALID_OPERATION, "glVertexAttribDivisor()"); return; @@ -1155,13 +1314,21 @@ _mesa_VertexAttribDivisor(GLuint index, GLuint divisor) return; } - ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(ctx->Array.ArrayObj->VertexAttrib)); + ASSERT(genericIndex < Elements(ctx->Array.ArrayObj->VertexAttrib)); - array = &ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)]; - if (array->InstanceDivisor != divisor) { - FLUSH_VERTICES(ctx, _NEW_ARRAY); - array->InstanceDivisor = divisor; - } + /* The ARB_vertex_attrib_binding spec says: + * + * "The command + * + * void VertexAttribDivisor(uint index, uint divisor); + * + * is equivalent to (assuming no errors are generated): + * + * VertexAttribBinding(index, index); + * VertexBindingDivisor(index, divisor);" + */ + vertex_attrib_binding(ctx, genericIndex, genericIndex); + vertex_binding_divisor(ctx, genericIndex, divisor); } @@ -1191,6 +1358,329 @@ _mesa_primitive_restart_index(const struct gl_context *ctx, GLenum ib_type) /** + * GL_ARB_vertex_attrib_binding + */ +void GLAPIENTRY +_mesa_BindVertexBuffer(GLuint bindingIndex, GLuint buffer, GLintptr offset, + GLsizei stride) +{ + GET_CURRENT_CONTEXT(ctx); + const struct gl_array_object *arrayObj = ctx->Array.ArrayObj; + struct gl_buffer_object *vbo; + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* The ARB_vertex_attrib_binding spec says: + * + * "An INVALID_OPERATION error is generated if no vertex array object + * is bound." + */ + if (ctx->API == API_OPENGL_CORE && + ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindVertexBuffer(No array object bound)"); + return; + } + + /* The ARB_vertex_attrib_binding spec says: + * + * "An INVALID_VALUE error is generated if <bindingindex> is greater than + * the value of MAX_VERTEX_ATTRIB_BINDINGS." + */ + if (bindingIndex >= ctx->Const.MaxVertexAttribBindings) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glBindVertexBuffer(bindingindex=%u > " + "GL_MAX_VERTEX_ATTRIB_BINDINGS)", + bindingIndex); + return; + } + + /* The ARB_vertex_attrib_binding spec says: + * + * "The error INVALID_VALUE is generated if <stride> or <offset> + * are negative." + */ + if (offset < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glBindVertexBuffer(offset=%lld < 0)", (long long)offset); + return; + } + + if (stride < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glBindVertexBuffer(stride=%d < 0)", stride); + return; + } + + if (buffer == arrayObj->VertexBinding[VERT_ATTRIB_GENERIC(bindingIndex)].BufferObj->Name) { + vbo = arrayObj->VertexBinding[VERT_ATTRIB_GENERIC(bindingIndex)].BufferObj; + } else if (buffer != 0) { + vbo = _mesa_lookup_bufferobj(ctx, buffer); + + /* From the GL_ARB_vertex_attrib_array spec: + * + * "[Core profile only:] + * An INVALID_OPERATION error is generated if buffer is not zero or a + * name returned from a previous call to GenBuffers, or if such a name + * has since been deleted with DeleteBuffers. + * + * Otherwise, we fall back to the same compat profile behavior as other + * object references (automatically gen it). + */ + if (!_mesa_handle_bind_buffer_gen(ctx, GL_ARRAY_BUFFER, buffer, + &vbo, "glBindVertexBuffer")) + return; + } else { + /* The ARB_vertex_attrib_binding spec says: + * + * "If <buffer> is zero, any buffer object attached to this + * bindpoint is detached." + */ + vbo = ctx->Shared->NullBufferObj; + } + + bind_vertex_buffer(ctx, VERT_ATTRIB_GENERIC(bindingIndex), + vbo, offset, stride); +} + + +void GLAPIENTRY +_mesa_VertexAttribFormat(GLuint attribIndex, GLint size, GLenum type, + GLboolean normalized, GLuint relativeOffset) +{ + const GLbitfield legalTypes = (BYTE_BIT | UNSIGNED_BYTE_BIT | + SHORT_BIT | UNSIGNED_SHORT_BIT | + INT_BIT | UNSIGNED_INT_BIT | + HALF_BIT | FLOAT_BIT | DOUBLE_BIT | + FIXED_GL_BIT | + UNSIGNED_INT_2_10_10_10_REV_BIT | + INT_2_10_10_10_REV_BIT | + UNSIGNED_INT_10F_11F_11F_REV_BIT); + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* The ARB_vertex_attrib_binding spec says: + * + * "An INVALID_OPERATION error is generated under any of the following + * conditions: + * - if no vertex array object is currently bound (see section 2.10); + * - ..." + */ + if (ctx->API == API_OPENGL_CORE && + ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glVertexAttribFormat(No array object bound)"); + return; + } + + /* The ARB_vertex_attrib_binding spec says: + * + * "The error INVALID_VALUE is generated if index is greater than or equal + * to the value of MAX_VERTEX_ATTRIBS." + */ + if (attribIndex >= ctx->Const.VertexProgram.MaxAttribs) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glVertexAttribFormat(attribindex=%u > " + "GL_MAX_VERTEX_ATTRIBS)", + attribIndex); + return; + } + + FLUSH_VERTICES(ctx, 0); + + update_array_format(ctx, "glVertexAttribFormat", + VERT_ATTRIB_GENERIC(attribIndex), + legalTypes, 1, BGRA_OR_4, size, type, normalized, + GL_FALSE, relativeOffset); +} + + +void GLAPIENTRY +_mesa_VertexAttribIFormat(GLuint attribIndex, GLint size, GLenum type, + GLuint relativeOffset) +{ + const GLbitfield legalTypes = (BYTE_BIT | UNSIGNED_BYTE_BIT | + SHORT_BIT | UNSIGNED_SHORT_BIT | + INT_BIT | UNSIGNED_INT_BIT); + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* The ARB_vertex_attrib_binding spec says: + * + * "An INVALID_OPERATION error is generated under any of the following + * conditions: + * - if no vertex array object is currently bound (see section 2.10); + * - ..." + */ + if (ctx->API == API_OPENGL_CORE && + ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glVertexAttribIFormat(No array object bound)"); + return; + } + + /* The ARB_vertex_attrib_binding spec says: + * + * "The error INVALID_VALUE is generated if index is greater than + * or equal to the value of MAX_VERTEX_ATTRIBS." + */ + if (attribIndex >= ctx->Const.VertexProgram.MaxAttribs) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glVertexAttribIFormat(attribindex=%u > " + "GL_MAX_VERTEX_ATTRIBS)", + attribIndex); + return; + } + + FLUSH_VERTICES(ctx, 0); + + update_array_format(ctx, "glVertexAttribIFormat", + VERT_ATTRIB_GENERIC(attribIndex), + legalTypes, 1, 4, size, type, GL_FALSE, GL_TRUE, + relativeOffset); +} + + +void GLAPIENTRY +_mesa_VertexAttribLFormat(GLuint attribIndex, GLint size, GLenum type, + GLuint relativeOffset) +{ + const GLbitfield legalTypes = DOUBLE_BIT; + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* Page 298 of the PDF of the OpenGL 4.3 (Core Profile) spec says: + * + * "An INVALID_OPERATION error is generated under any of the following + * conditions: + * • if no vertex array object is currently bound (see section 10.4); + * • ..." + * + * This language is missing from the extension spec, but we assume + * that this is an oversight. + */ + if (ctx->API == API_OPENGL_CORE && + ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glVertexAttribLFormat(No array object bound)"); + return; + } + + /* The ARB_vertex_attrib_binding spec says: + * + * "The error INVALID_VALUE is generated if <attribindex> is greater than + * or equal to the value of MAX_VERTEX_ATTRIBS." + */ + if (attribIndex >= ctx->Const.VertexProgram.MaxAttribs) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glVertexAttribLFormat(attribindex=%u > " + "GL_MAX_VERTEX_ATTRIBS)", + attribIndex); + return; + } + + FLUSH_VERTICES(ctx, 0); + + update_array_format(ctx, "glVertexAttribLFormat", + VERT_ATTRIB_GENERIC(attribIndex), + legalTypes, 1, 4, size, type, GL_FALSE, GL_FALSE, + relativeOffset); +} + + +void GLAPIENTRY +_mesa_VertexAttribBinding(GLuint attribIndex, GLuint bindingIndex) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* The ARB_vertex_attrib_binding spec says: + * + * "An INVALID_OPERATION error is generated if no vertex array object + * is bound." + */ + if (ctx->API == API_OPENGL_CORE && + ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glVertexAttribBinding(No array object bound)"); + return; + } + + /* The ARB_vertex_attrib_binding spec says: + * + * "<attribindex> must be less than the value of MAX_VERTEX_ATTRIBS and + * <bindingindex> must be less than the value of + * MAX_VERTEX_ATTRIB_BINDINGS, otherwise the error INVALID_VALUE + * is generated." + */ + if (attribIndex >= ctx->Const.VertexProgram.MaxAttribs) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glVertexAttribBinding(attribindex=%u >= " + "GL_MAX_VERTEX_ATTRIBS)", + attribIndex); + return; + } + + if (bindingIndex >= ctx->Const.MaxVertexAttribBindings) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glVertexAttribBinding(bindingindex=%u >= " + "GL_MAX_VERTEX_ATTRIB_BINDINGS)", + bindingIndex); + return; + } + + ASSERT(VERT_ATTRIB_GENERIC(attribIndex) < + Elements(ctx->Array.ArrayObj->VertexAttrib)); + + vertex_attrib_binding(ctx, VERT_ATTRIB_GENERIC(attribIndex), + VERT_ATTRIB_GENERIC(bindingIndex)); +} + + +void GLAPIENTRY +_mesa_VertexBindingDivisor(GLuint bindingIndex, GLuint divisor) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (!ctx->Extensions.ARB_instanced_arrays) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glVertexBindingDivisor()"); + return; + } + + /* The ARB_vertex_attrib_binding spec says: + * + * "An INVALID_OPERATION error is generated if no vertex array object + * is bound." + */ + if (ctx->API == API_OPENGL_CORE && + ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glVertexBindingDivisor(No array object bound)"); + return; + } + + /* The ARB_vertex_attrib_binding spec says: + * + * "An INVALID_VALUE error is generated if <bindingindex> is greater + * than or equal to the value of MAX_VERTEX_ATTRIB_BINDINGS." + */ + if (bindingIndex >= ctx->Const.MaxVertexAttribBindings) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glVertexBindingDivisor(bindingindex=%u > " + "GL_MAX_VERTEX_ATTRIB_BINDINGS)", + bindingIndex); + return; + } + + vertex_binding_divisor(ctx, VERT_ATTRIB_GENERIC(bindingIndex), divisor); +} + + +/** * Copy one client vertex array to another. */ void @@ -1213,7 +1703,36 @@ _mesa_copy_client_array(struct gl_context *ctx, dst->_MaxElement = src->_MaxElement; } +void +_mesa_copy_vertex_attrib_array(struct gl_context *ctx, + struct gl_vertex_attrib_array *dst, + const struct gl_vertex_attrib_array *src) +{ + dst->Size = src->Size; + dst->Type = src->Type; + dst->Format = src->Format; + dst->VertexBinding = src->VertexBinding; + dst->RelativeOffset = src->RelativeOffset; + dst->Format = src->Format; + dst->Integer = src->Integer; + dst->Normalized = src->Normalized; + dst->Ptr = src->Ptr; + dst->Enabled = src->Enabled; + dst->_ElementSize = src->_ElementSize; +} +void +_mesa_copy_vertex_buffer_binding(struct gl_context *ctx, + struct gl_vertex_buffer_binding *dst, + const struct gl_vertex_buffer_binding *src) +{ + dst->Offset = src->Offset; + dst->Stride = src->Stride; + dst->InstanceDivisor = src->InstanceDivisor; + dst->_BoundArrays = src->_BoundArrays; + + _mesa_reference_buffer_object(ctx, &dst->BufferObj, src->BufferObj); +} /** * Print vertex array's fields. @@ -1245,18 +1764,18 @@ _mesa_print_arrays(struct gl_context *ctx) _mesa_update_array_object_max_element(ctx, arrayObj); printf("Array Object %u\n", arrayObj->Name); - if (arrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled) - print_array("Vertex", -1, &arrayObj->VertexAttrib[VERT_ATTRIB_POS]); - if (arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL].Enabled) - print_array("Normal", -1, &arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL]); - if (arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0].Enabled) - print_array("Color", -1, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0]); + if (arrayObj->_VertexAttrib[VERT_ATTRIB_POS].Enabled) + print_array("Vertex", -1, &arrayObj->_VertexAttrib[VERT_ATTRIB_POS]); + if (arrayObj->_VertexAttrib[VERT_ATTRIB_NORMAL].Enabled) + print_array("Normal", -1, &arrayObj->_VertexAttrib[VERT_ATTRIB_NORMAL]); + if (arrayObj->_VertexAttrib[VERT_ATTRIB_COLOR0].Enabled) + print_array("Color", -1, &arrayObj->_VertexAttrib[VERT_ATTRIB_COLOR0]); for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) - if (arrayObj->VertexAttrib[VERT_ATTRIB_TEX(i)].Enabled) - print_array("TexCoord", i, &arrayObj->VertexAttrib[VERT_ATTRIB_TEX(i)]); + if (arrayObj->_VertexAttrib[VERT_ATTRIB_TEX(i)].Enabled) + print_array("TexCoord", i, &arrayObj->_VertexAttrib[VERT_ATTRIB_TEX(i)]); for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; i++) - if (arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(i)].Enabled) - print_array("Attrib", i, &arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(i)]); + if (arrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC(i)].Enabled) + print_array("Attrib", i, &arrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC(i)]); printf(" _MaxElement = %u\n", arrayObj->_MaxElement); } diff --git a/mesalib/src/mesa/main/varray.h b/mesalib/src/mesa/main/varray.h index 7e611e8c7..8a9487c6e 100644 --- a/mesalib/src/mesa/main/varray.h +++ b/mesalib/src/mesa/main/varray.h @@ -29,6 +29,7 @@ #include "glheader.h" +#include "bufferobj.h" struct gl_client_array; struct gl_context; @@ -50,8 +51,10 @@ _mesa_update_array_max_element(struct gl_client_array *array) GLsizeiptrARB bufSize = (GLsizeiptrARB) array->BufferObj->Size; if (offset < bufSize) { - array->_MaxElement = (bufSize - offset + array->StrideB - - array->_ElementSize) / array->StrideB; + const GLuint stride = array->StrideB ? + array->StrideB : array->_ElementSize; + array->_MaxElement = (bufSize - offset + stride + - array->_ElementSize) / stride; } else { array->_MaxElement = 0; @@ -64,6 +67,44 @@ _mesa_update_array_max_element(struct gl_client_array *array) } +/** + * Returns a pointer to the vertex attribute data in a client array, + * or the offset into the vertex buffer for an array that resides in + * a vertex buffer. + */ +static inline const GLubyte * +_mesa_vertex_attrib_address(struct gl_vertex_attrib_array *array, + struct gl_vertex_buffer_binding *binding) +{ + return (binding->BufferObj->Name == 0 ? + array->Ptr : + (const GLubyte *)(binding->Offset + array->RelativeOffset)); +} + +/** + * Sets the fields in a gl_client_array to values derived from a + * gl_vertex_attrib_array and a gl_vertex_buffer_binding. + */ +static inline void +_mesa_update_client_array(struct gl_context *ctx, + struct gl_client_array *dst, + struct gl_vertex_attrib_array *src, + struct gl_vertex_buffer_binding *binding) +{ + dst->Size = src->Size; + dst->Type = src->Type; + dst->Format = src->Format; + dst->Stride = src->Stride; + dst->StrideB = binding->Stride; + dst->Ptr = _mesa_vertex_attrib_address(src, binding); + dst->Enabled = src->Enabled; + dst->Normalized = src->Normalized; + dst->Integer = src->Integer; + dst->InstanceDivisor = binding->InstanceDivisor; + dst->_ElementSize = src->_ElementSize; + _mesa_reference_buffer_object(ctx, &dst->BufferObj, binding->BufferObj); +} + extern void GLAPIENTRY _mesa_VertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); @@ -250,11 +291,43 @@ _mesa_VertexAttribDivisor(GLuint index, GLuint divisor); extern unsigned _mesa_primitive_restart_index(const struct gl_context *ctx, GLenum ib_type); +extern void GLAPIENTRY +_mesa_BindVertexBuffer(GLuint bindingIndex, GLuint buffer, GLintptr offset, + GLsizei stride); + +extern void GLAPIENTRY +_mesa_VertexAttribFormat(GLuint attribIndex, GLint size, GLenum type, + GLboolean normalized, GLuint relativeOffset); + +extern void GLAPIENTRY +_mesa_VertexAttribIFormat(GLuint attribIndex, GLint size, GLenum type, + GLuint relativeOffset); + +extern void GLAPIENTRY +_mesa_VertexAttribLFormat(GLuint attribIndex, GLint size, GLenum type, + GLuint relativeOffset); + +extern void GLAPIENTRY +_mesa_VertexAttribBinding(GLuint attribIndex, GLuint bindingIndex); + +extern void GLAPIENTRY +_mesa_VertexBindingDivisor(GLuint bindingIndex, GLuint divisor); + + extern void _mesa_copy_client_array(struct gl_context *ctx, struct gl_client_array *dst, struct gl_client_array *src); +extern void +_mesa_copy_vertex_attrib_array(struct gl_context *ctx, + struct gl_vertex_attrib_array *dst, + const struct gl_vertex_attrib_array *src); + +extern void +_mesa_copy_vertex_buffer_binding(struct gl_context *ctx, + struct gl_vertex_buffer_binding *dst, + const struct gl_vertex_buffer_binding *src); extern void _mesa_print_arrays(struct gl_context *ctx); diff --git a/mesalib/src/mesa/state_tracker/st_atom_array.c b/mesalib/src/mesa/state_tracker/st_atom_array.c index 87a0a17f1..76a94bcf8 100644 --- a/mesalib/src/mesa/state_tracker/st_atom_array.c +++ b/mesalib/src/mesa/state_tracker/st_atom_array.c @@ -214,7 +214,8 @@ st_pipe_vertex_format(GLenum type, GLuint size, GLenum format, assert((type >= GL_BYTE && type <= GL_DOUBLE) || type == GL_FIXED || type == GL_HALF_FLOAT || type == GL_INT_2_10_10_10_REV || - type == GL_UNSIGNED_INT_2_10_10_10_REV); + type == GL_UNSIGNED_INT_2_10_10_10_REV || + type == GL_UNSIGNED_INT_10F_11F_11F_REV); assert(size >= 1); assert(size <= 4); assert(format == GL_RGBA || format == GL_BGRA); @@ -251,6 +252,14 @@ st_pipe_vertex_format(GLenum type, GLuint size, GLenum format, } } + if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) { + assert(size == 3); + assert(!integer); + assert(format == GL_RGBA); + + return PIPE_FORMAT_R11G11B10_FLOAT; + } + if (format == GL_BGRA) { /* this is an odd-ball case */ assert(type == GL_UNSIGNED_BYTE); diff --git a/mesalib/src/mesa/state_tracker/st_extensions.c b/mesalib/src/mesa/state_tracker/st_extensions.c index 97c5d55e1..e8d0902d9 100644 --- a/mesalib/src/mesa/state_tracker/st_extensions.c +++ b/mesalib/src/mesa/state_tracker/st_extensions.c @@ -507,6 +507,8 @@ void st_init_extensions(struct st_context *st) PIPE_FORMAT_B10G10R10A2_USCALED, PIPE_FORMAT_R10G10B10A2_SSCALED, PIPE_FORMAT_B10G10R10A2_SSCALED } }, + { { o(ARB_vertex_type_10f_11f_11f_rev) }, + { PIPE_FORMAT_R11G11B10_FLOAT } }, }; static const struct st_extension_format_mapping tbo_rgb32[] = { diff --git a/mesalib/src/mesa/vbo/vbo_attrib_tmp.h b/mesalib/src/mesa/vbo/vbo_attrib_tmp.h index bbc020539..358d12d15 100644 --- a/mesalib/src/mesa/vbo/vbo_attrib_tmp.h +++ b/mesalib/src/mesa/vbo/vbo_attrib_tmp.h @@ -25,6 +25,8 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. **************************************************************************/ +#include "util/u_format_r11g11b10f.h" + /* float */ #define ATTR1FV( A, V ) ATTR( A, 1, GL_FLOAT, (V)[0], 0, 0, 1 ) #define ATTR2FV( A, V ) ATTR( A, 2, GL_FLOAT, (V)[0], (V)[1], 0, 1 ) @@ -205,6 +207,10 @@ static inline float conv_i2_to_norm_float(const struct gl_context *ctx, int i2) } else { \ ATTRI10_##val((attr), (arg)); \ } \ + } else if ((type) == GL_UNSIGNED_INT_10F_11F_11F_REV) { \ + float res[4]; \ + r11g11b10f_to_float3((arg), res); \ + ATTR##val##FV((attr), res); \ } else \ ERROR(GL_INVALID_VALUE); \ } while(0) @@ -835,12 +841,26 @@ TAG(VertexAttrib4fvNV)(GLuint index, const GLfloat * v) ATTR4FV(index, v); } + #define ERROR_IF_NOT_PACKED_TYPE(ctx, type, func) \ if (type != GL_INT_2_10_10_10_REV && type != GL_UNSIGNED_INT_2_10_10_10_REV) { \ _mesa_error(ctx, GL_INVALID_ENUM, "%s(type)", func); \ return; \ } +/* Extended version of ERROR_IF_NOT_PACKED_TYPE which also + * accepts GL_UNSIGNED_INT_10F_11F_11F_REV. + * + * Only used for VertexAttribP[123]ui[v]; VertexAttribP4* cannot use this type, + * and neither can legacy vertex attribs. + */ +#define ERROR_IF_NOT_PACKED_TYPE_EXT(ctx, type, func) \ + if (type != GL_INT_2_10_10_10_REV && type != GL_UNSIGNED_INT_2_10_10_10_REV && \ + type != GL_UNSIGNED_INT_10F_11F_11F_REV) { \ + _mesa_error(ctx, GL_INVALID_ENUM, "%s(type)", func); \ + return; \ + } + static void GLAPIENTRY TAG(VertexP2ui)(GLenum type, GLuint value) { @@ -1094,7 +1114,7 @@ TAG(VertexAttribP1ui)(GLuint index, GLenum type, GLboolean normalized, GLuint value) { GET_CURRENT_CONTEXT(ctx); - ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexAttribP1ui"); + ERROR_IF_NOT_PACKED_TYPE_EXT(ctx, type, "glVertexAttribP1ui"); ATTR_UI_INDEX(ctx, 1, type, normalized, index, value); } @@ -1103,7 +1123,7 @@ TAG(VertexAttribP2ui)(GLuint index, GLenum type, GLboolean normalized, GLuint value) { GET_CURRENT_CONTEXT(ctx); - ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexAttribP2ui"); + ERROR_IF_NOT_PACKED_TYPE_EXT(ctx, type, "glVertexAttribP2ui"); ATTR_UI_INDEX(ctx, 2, type, normalized, index, value); } @@ -1112,7 +1132,7 @@ TAG(VertexAttribP3ui)(GLuint index, GLenum type, GLboolean normalized, GLuint value) { GET_CURRENT_CONTEXT(ctx); - ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexAttribP3ui"); + ERROR_IF_NOT_PACKED_TYPE_EXT(ctx, type, "glVertexAttribP3ui"); ATTR_UI_INDEX(ctx, 3, type, normalized, index, value); } @@ -1130,7 +1150,7 @@ TAG(VertexAttribP1uiv)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value) { GET_CURRENT_CONTEXT(ctx); - ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexAttribP1uiv"); + ERROR_IF_NOT_PACKED_TYPE_EXT(ctx, type, "glVertexAttribP1uiv"); ATTR_UI_INDEX(ctx, 1, type, normalized, index, *value); } @@ -1139,7 +1159,7 @@ TAG(VertexAttribP2uiv)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value) { GET_CURRENT_CONTEXT(ctx); - ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexAttribP2uiv"); + ERROR_IF_NOT_PACKED_TYPE_EXT(ctx, type, "glVertexAttribP2uiv"); ATTR_UI_INDEX(ctx, 2, type, normalized, index, *value); } @@ -1148,7 +1168,7 @@ TAG(VertexAttribP3uiv)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value) { GET_CURRENT_CONTEXT(ctx); - ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexAttribP3uiv"); + ERROR_IF_NOT_PACKED_TYPE_EXT(ctx, type, "glVertexAttribP3uiv"); ATTR_UI_INDEX(ctx, 3, type, normalized, index, *value); } diff --git a/mesalib/src/mesa/vbo/vbo_exec_array.c b/mesalib/src/mesa/vbo/vbo_exec_array.c index f25a9dec3..d72382376 100644 --- a/mesalib/src/mesa/vbo/vbo_exec_array.c +++ b/mesalib/src/mesa/vbo/vbo_exec_array.c @@ -318,8 +318,8 @@ check_draw_elements_data(struct gl_context *ctx, GLsizei count, GLenum elemType, } /* check element j of each enabled array */ - for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) { - check_array_data(ctx, &arrayObj->VertexAttrib[k], k, j); + for (k = 0; k < Elements(arrayObj->_VertexAttrib); k++) { + check_array_data(ctx, &arrayObj->_VertexAttrib[k], k, j); } } @@ -327,8 +327,8 @@ check_draw_elements_data(struct gl_context *ctx, GLsizei count, GLenum elemType, ctx->Driver.UnmapBuffer(ctx, ctx->Array.ArrayObj->ElementArrayBufferObj); } - for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) { - unmap_array_buffer(ctx, &arrayObj->VertexAttrib[k]); + for (k = 0; k < Elements(arrayObj->_VertexAttrib); k++) { + unmap_array_buffer(ctx, &arrayObj->_VertexAttrib[k]); } } @@ -368,7 +368,7 @@ print_draw_arrays(struct gl_context *ctx, exec->array.inputs[i]->Size, stride, /*exec->array.inputs[i]->Enabled,*/ - arrayObj->VertexAttrib[VERT_ATTRIB_FF(i)].Enabled, + arrayObj->_VertexAttrib[VERT_ATTRIB_FF(i)].Enabled, exec->array.inputs[i]->Ptr, bufName); @@ -405,7 +405,7 @@ recalculate_input_bindings(struct gl_context *ctx) { struct vbo_context *vbo = vbo_context(ctx); struct vbo_exec_context *exec = &vbo->exec; - struct gl_client_array *vertexAttrib = ctx->Array.ArrayObj->VertexAttrib; + struct gl_client_array *vertexAttrib = ctx->Array.ArrayObj->_VertexAttrib; const struct gl_client_array **inputs = &exec->array.inputs[0]; GLbitfield64 const_inputs = 0x0; GLuint i; diff --git a/mesalib/src/mesa/x86/Makefile.am b/mesalib/src/mesa/x86/Makefile.am deleted file mode 100644 index 167857684..000000000 --- a/mesalib/src/mesa/x86/Makefile.am +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright © 2012 Intel Corporation -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice (including the next -# paragraph) shall be included in all copies or substantial portions of the -# Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -# IN THE SOFTWARE. - -if HAVE_X86_ASM - -AM_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I$(top_srcdir)/src/mesa \ - -I$(top_srcdir)/src/mapi \ - $(DEFINES) - -noinst_PROGRAMS = gen_matypes - -gen_matypes_SOURCES = gen_matypes.c -BUILT_SOURCES = matypes.h -CLEANFILES = matypes.h - -if GEN_ASM_OFFSETS - -matypes.h: $(gen_matypes_SOURCES) - $(AM_V_GEN)$(COMPILE) $< -DASM_OFFSETS -S -o - | \ - sed -n '/^->/{s:^->::;/[$$]/{s:^:#define :;s:[$$]::};p}' > $@ - -else - -matypes.h: gen_matypes - $(AM_V_GEN)./gen_matypes > $@ - -endif - -endif |