Name AMD_framebuffer_sample_positions Name Strings GL_AMD_framebuffer_sample_positions Contact Mais Alnasser, AMD (mais.alnasser 'at' amd.com) Contributors Mais Alnasser, AMD Graham Sellers, AMD Status Shipping Version Last Modified Date: 11/10/16 Revision: 4 Number OpenGL Extension #454 Dependencies OpenGL 3.2 is required. This specification interacts with EXT_direct_state_access. This extension is written against the OpenGL 4.4 (Core) specification. Overview In unextended GL, the sub-pixel loations of multisampled textures and renderbuffers are generally determined in an implementation dependent manner. Some algorithms -- in particular custom antialiasing functions -- depend on the knowledge of, or even require control over the positions of samples within each pixel. The AMD_sample_positions extension added some control over the positions of samples within a single framebuffer. However, it forced all pixels within a framebuffer to have the set of sample positions. This extension provides a mechanism to explicitly set sample positions for a framebuffer object with multi-sampled attachments in a repeating pattern, allowing different pixels to use different sub-pixel locations for their samples. The sample locations used by the FBO can be fixed for all pixels in the FBO’s attachments or they can be fixed for a sampling pattern comprised of multiple pixels, where the sampling pattern is repeated over all pixels. The rate of repeat of this sampling pattern size itself is fixed and is implementation-dependent. New Tokens Accepted by the parameter of GetFloatv: SUBSAMPLE_DISTANCE_AMD 0x883F Accepted by the parameter of GetIntegerv: PIXELS_PER_SAMPLE_PATTERN_X_AMD 0x91AE PIXELS_PER_SAMPLE_PATTERN_Y_AMD 0x91AF Accepted by the parameter of FramebufferSamplePositionsfvAMD, NamedFramebufferSamplePositionsfvAMD, GetFramebufferParameterfvAMD and GetNamedFramebufferParameterfvAMD: ALL_PIXELS_AMD 0xFFFFFFFF New Procedures and Functions void FramebufferSamplePositionsfvAMD(enum target, uint numsamples, uint pixelindex, const float *values) void NamedFramebufferSamplePositionsfvAMD(uint framebuffer, uint numsamples, uint pixelindex, const float *values) void GetFramebufferParameterfvAMD(enum target, enum pname, uint numsamples, uint pixelindex, sizei size, float *values) void GetNamedFramebufferParameterfvAMD(uint framebuffer, enum pname, uint numsamples, uint pixelindex, sizei size, float *values) Additions to Chapter 9 of the OpenGL 4.4 (Core) Specification (Framebuffers and Framebuffer Objects) Add section 9.2.9, Framebuffer Sample Positions, p. 287 Sample locations can be modified for all pixels in a multi-sampled framebuffer using the following command: void FramebufferSamplePositionsfvAMD(enum target, uint numsamples, uint pixelindex, const float *values); must be DRAW_FRAMEBUFFER, READ_FRAMEBUFFER, or FRAMEBUFFER. is the number of samples to set and must be greater than 0 and less than or equal to the value of SAMPLES. The error INVALID_VALUE is generated if is outside this range. is the index of the pixel to set the samples for and must be greater than or equal to 0 and less than the result of querying PIXELS_PER_SAMPLE_PATTERN_X_AMD multiplied by the result of querying PIXELS_PER_SAMPLE_PATTERN_Y_AMD. The pixels are ordered left to right, top to bottom, where the origin is the upper left corner. may also specify ALL_PIXELS_AMD, which sets samples of all pixels to the same set of locations. The error INVALID_VALUE is generated if is less than zero or is greater than or equal to the result of querying PIXELS_PER_SAMPLE_PATTERN_X_AMD multiplied by the result of querying PIXELS_PER_SAMPLE_PATTERN_Y_AMD and is not equal to ALL_PIXELS_AMD. The sample locations are set by passing floating point values of x and y in and respectively, all in the range [0.0, 1.0), corresponding to the and locations in pixel space of that sample, respectively. (0.5, 0.5) thus corresponds to the pixel center. The range [0.0, 0.1) implies that sample locations cannot overlap at pixel boundaries. FramebufferSamplePositionsfvAMD generates an INVALID_OPERATION error if the currently bound framebuffer is incomplete or is the default framebuffer. If is NULL, is ignored and all sample positions for are returned to their default values. Passing ALL_PIXELS_AMD therefore resets the sample positions for all pixels in the sampling pattern. The subpixel range [0,1) is discretized based on the implementation- dependent value of SUBSAMPLE_DISTANCE_AMD. GetFloatv can be used with SUBSAMPLE_DISTANCE_AMD as the pname parameter to query the subpixel precision, which is the same for both the vertical and horizontal directions. Given two sample positions (x0, y0) and (x1, y1), one can make sure they don't fall in the same subpixel if abs(x0 - x1) >= ssd and abs(y0 - y1) >= ssd, where ssd is the float value returned when querying SUBSAMPLE_DISTANCE_AMD. The quantized sample positions can be retrieved via the new entry point: void GetFramebufferParameterfvAMD(enum target, enum pname, uint numsamples, uint pixelindex, sizei size, float *values); must be DRAW_FRAMEBUFFER, READ_FRAMEBUFFER, or FRAMEBUFFER. FRAMEBUFFER is equivalent to DRAW_FRAMEBUFFER. must be SAMPLE_POSITIONS. is the number of samples to get and must be greater than 0 and less than or equal to the value of SAMPLES. The error INVALID_VALUE is generated if is outside this range. is the index of the pixel to set the samples for and must be less than the result of querying PIXELS_PER_SAMPLE_PATTERN_X_AMD multiplied by the result of querying PIXELS_PER_SAMPLE_PATTERN_Y_AMD. Calling GetFramebufferParameterfvAMD with within this range retrieves the set of sample positions for the pixel matching . can also be equal to ALL_PIXELS_AMD, which would cause the function to return an array of the requested per each pixel in the sampling pattern. The error INVALID_VALUE is generated if is less than zero or is greater than or equal to the result of querying PIXELS_PER_SAMPLE_PATTERN_X_AMD multiplied by the result of querying PIXELS_PER_SAMPLE_PATTERN_Y_AMD and is not equal to ALL_SAMPLES. The samples returned are ordered per pixel, and the order of the pixels would be left to right, then top to bottom, where the sampling pattern origin is the upper left corner. is the requested size of the retrieved sample locations in bytes. will contain the returned and coordinates of the requested samples in pixel space. The sample locations returned are all in the range [0, 1), corresponding to the and locations in pixel space of that sample, respectively. (0.5, 0.5) thus corresponds to the pixel center. The commands: void NamedFramebufferSamplePositionsfvAMD(uint framebuffer, uint numsamples, uint pixelindex, const float *values); void GetNamedFramebufferParameterfvAMD(uint framebuffer, enum pname, uint numsamples, uint pixelindex, sizei size, float *value); behave identically to FramebufferSamplePositionsfvAMD and GetFramebufferSampleParameterfvAMD, except that the target of the operation is the framebuffer object named rather than the object bound to a specified target. If is not the name of an existing framebuffer object an INVALID_OPERATION error is generated. Additions to Chapter 14 of the OpenGL 4.4 (Core) Specification (Fixed-Function Primitive Assembly and Rasterization) (Modify Section 14.3, Antialiasing, p. 412) Add after the segment: "If the multisample mode does not have fixed sample locations, the returned values may only reflect the locations of samples within some pixels.", append: If GetMultisamplefv is used to query the result of using FramebufferSamplePositionsfvAMD or NamedFramebufferSamplePositionsfvAMD with ALL_PIXELS_AMD, the returned sample position matches that of equal to zero. Errors INVALID_VALUE is generated by FramebufferSamplePositionsfvAMD, NamedFramebufferSamplePositionsfvAMD, GetFramebufferParameterfvAMD and GetNamedFramebufferParameterfvAMD if numsamples is greater than the value of SAMPLES. INVALID_VALUE is generated by FramebufferSamplePositionsfvAMD if pixelindex is greater than or equal to the value of NUM_PIXELS_PER_SAMPLE_PATTERN_X_AMD * NUM_PIXELS_PER_SAMPLE_PATTERN_Y_AMD and is not equal to ALL_SAMPLES_AMD. INVALID_OPERATION is generated by FramebufferSamplePositionsfvAMD if the currently bound framebuffer is the default framebuffer. INVALID_OPERATION is generated by NamedFramebufferSamplePositionsfvAMD if the is not the name of an existing framebufer object. INVALID_OPERATION is generated by FramebufferSamplePositionsfvAMD if the currently bound framebuffer is incomplete. INVALID_OPERATION is generated by NamedFramebufferSamplePositionsfvAMD if the is incomplete. New State Add to Table 23.24, Framebuffer (state per framebuffer object), p. 545: Get Value Type Get Command Value Description Sec. --------- ---- ----------- ----- ------------------------------ ----- SAMPLE_POSITIONS 2xR+ GetFramebufferParameterfvAMD The (x, y) sample locations in 9.2.9 the range [0, 1) New Implementation Dependent State Add to Table 23.11, Multisampling, p. 532: Get Value Type Get Command Value Description Sec. --------- ------- ----------- ------- ------------------------ ----- SUBSAMPLE_DISTANCE_AMD R+ GetFloatv precision step between 9.2.9 subsamples PIXELS_PER_SAMPLE_PATTERN_X_AMD Z+ GetIntegerv number of pixels in the 9.2.9 X direction PIXELS_PER_SAMPLE_PATTERN_Y_AMD Z+ GetIntegerv number of pixels in the 9.2.9 Y direction Interaction with ARB_texture_multisample If ARB_texture_multisample is not supported, remove all references to GetMultisamplefv. Dependencies on EXT_direct_state_access If EXT_direct_state_access is not supported, remove references to the Named* commands added by this extension. Issues (1) What happens if an app just sets one sample position? RESOLVED: Any attachment to the bound FBO will have the index 0 position updated. All the rest of the positions will keep their original values. Any other FBOs will not be affected by this change. (2) Should we also expose the precision? Can an app use it in setting sample positions? RESOLVED: SUBSAMPLE_DISTANCE_AMD is added as a new token. It can be used by GetFloatv to query the precision step, which will be the same for both the vertical and horizontal directions. The subpixel range [0,1) is discretized based on the value of SUBSAMPLE_DISTANCE_AMD. Let ssd be the float value returned when SUBSAMPLE_DISTANCE_AMD is queried, then one can infer the subpixilization to be 1/ssd+1. For example, if ssd = 0.06667 then the pixel is subdivided into 1/0.0667+1 = 16 subpixels in each dimension. One can also avoid using sample positions that would map to the same subpixel. A coordinate c will map to the greatest multiple of ssd that is less or equal to c. For example, given two sample positions, (x0, y0) and (x1, y1), if abs(x1-x0) < ssd and abs(y1-y0) < ssd, then both points will map to the same subpixel, which means the application might want to substitute one of these positions with another that is not redundant. Using numerical values as an example, let a = (0.201, 0.0) and b = (0.25, 0.5) be sample positions and ssd = 0.06667. Both the x-coordinate values 0.201 and 0.25 fall between 0.06667*3=0.2 and 0.06667*4 = 0.26667 and would therefore map to the same value of 0.2. The y-coordinates also map to the same value of 0 because they both belong in the range [0, 0.06667). This means the two points are redundant. Therefore, the application should choose a different point c = (0.3, 0.45) for example. c would be a good choice because the distance between its x-coordinate and a's x-coordinate is greater than ssd, that is 0.3-0.201 > 0.06667. (3) What would be the expected results for the following scenarios: Scenario 1 The current number of samples in the framebuffer is 8. The application requests 5 sample positions and GL_ALL_PIXELS. The application passes 22*2*sizeof(GLuint) as the size in bytes (more than needed). RESOLVED: The returned array would have a capped size of 20*2*sizeof(GLuint) and will contain the first 5 samples of pixel (x0, y0), then the first 5 samples of pixel (x1, y0), then the first 5 samples of pixel (x0, y1) and finally the first 5 samples of pixel (x1, y1). Scenario 2 The current number of samples in the framebuffer is 8. The application requests 5 sample positions and GL_ALL_PIXELS. The application passes 18*2*sizeof(GLuint) as the size in bytes (less than needed). RESOLVED: The returned array would have a size of 18*2*sizeof(GLuint) and will contain the first 5 samples of pixel (x0, y0), then the first 5 samples of pixel (x1, y0), then the first 5 samples of pixel (x0, y1) and finally the first 3 samples of pixel (x1, y1). Scenario 3 The current number of samples in the framebuffer is 8. The application requests 5 sample positions and GL_ALL_PIXELS. The application passes 12*2*sizeof(GLuint) as the size in bytes (less than needed). RESOLVED: The returned array would have a size of 12*2*sizeof(GLuint) and will contain the first 5 samples of pixel (x0, y0), then the first 5 samples of pixel (x1, y0), and the first 2 samples of pixel (x0, y1). (4) What is the expected behavior of a multisampled texture is attached with equal to TRUE and then the application attempts to set different samples per pixels in a sampling pattern? RESOLVED: If is set to TRUE, the sample positions in equaling zero get replicated to all other pixels in the sampling pattern. (5) What is the result of rendering to a framebuffer, changing its sample locations and then rendering again into that framebuffer without clearing it first? RESOLVED: The result is effectively undefined. The result of rendering will not be consistent between the two passes. No ill effect should come of this, but the framebuffer content may appear corrupted. Revision History Rev. Date Author Changes ---- -------- -------- ----------------------------------------- 4 11/10/16 malnasse Modify the 'framebuffer' parameter in GetNamedFramebufferParameterfvAMD from GLenum to GLuint to match the DSA style. 3 11/09/16 malnasse Update PIXELS_PER_SAMPLE_PATTERN_X_AMD and PIXELS_PER_SAMPLE_PATTERN_Y_AMD token values. 2 04/18/14 gsellers Ready for posting. 1 10/14/13 malnasse First revision.