regal/tests/testRegalPpca.cpp
Nigel Stewart 0c089bf5bc DispatcherGlobal added for global (GLX/WGL/EGL) API dispatch layering.
Work-in-progress: apitrace dispatch layer for Regal, not enabled yet.
Added All.sln for VC10 purposes.
2013-06-05 23:06:03 -05:00

2077 lines
88 KiB
C++

/*
Copyright (c) 2011-2012 NVIDIA Corporation
Copyright (c) 2011-2012 Cass Everitt
Copyright (c) 2012 Scott Nations
Copyright (c) 2012 Mathias Schott
Copyright (c) 2012 Nigel Stewart
Copyright (c) 2013 Google Inc
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "RegalContext.h"
#include "RegalContextInfo.h"
#include "RegalDispatchGMock.h"
#include "RegalPpca.h"
namespace {
using namespace Regal;
using namespace Regal::Emu;
using ::testing::Mock;
template <typename T, size_t N> size_t arraysize( const T( & )[ N ] ) {
return N;
}
// ====================================
// ClientState::PixelStore::State
// ====================================
TEST( RegalClientStatePixelStore, SizesAndMappings ) {
using namespace ClientState::PixelStore;
using ClientState::PixelStore::State;
using ClientState::PixelStore::PNameToIndex;
// The arrays for the state data and mapping must match the number of
// named attributes the state supports.
ASSERT_EQ( STATE_COUNT, arraysize( static_cast<const State *>( NULL )->data ) );
ASSERT_EQ( STATE_COUNT, arraysize( State::indexToPName ) );
// Test the round trip mapping from index to name and back)
for ( size_t i = 0; i < STATE_COUNT; ++i ) {
EXPECT_EQ( i, PNameToIndex( State::indexToPName[ i ] ) );
}
// Unexpected names should return an invalid index.
EXPECT_EQ( INVALID_INDEX, PNameToIndex( GL_PACK_SWAP_BYTES - 1 ) );
}
TEST( RegalClientStatePixelStore, BasicOperations ) {
using ClientState::PixelStore::State;
using ClientState::PixelStore::PNameToIndex;
State state;
state.Reset();
State other;
other.Reset();
// It should be possible to set each attribute in a state to a unique
// value.
other.Set( GL_PACK_SWAP_BYTES , 11 );
other.Set( GL_PACK_LSB_FIRST , 12 );
other.Set( GL_PACK_ROW_LENGTH , 13 );
other.Set( GL_PACK_IMAGE_HEIGHT , 14 );
other.Set( GL_PACK_SKIP_ROWS , 15 );
other.Set( GL_PACK_SKIP_PIXELS , 16 );
other.Set( GL_PACK_SKIP_IMAGES , 17 );
other.Set( GL_PACK_ALIGNMENT , 18 );
other.Set( GL_UNPACK_SWAP_BYTES , 21 );
other.Set( GL_UNPACK_LSB_FIRST , 22 );
other.Set( GL_UNPACK_ROW_LENGTH , 23 );
other.Set( GL_UNPACK_IMAGE_HEIGHT , 24 );
other.Set( GL_UNPACK_SKIP_ROWS , 25 );
other.Set( GL_UNPACK_SKIP_PIXELS , 26 );
other.Set( GL_UNPACK_SKIP_IMAGES , 27 );
other.Set( GL_UNPACK_ALIGNMENT , 28 );
other.pixelPackBufferBinding = 100;
other.pixelUnpackBufferBinding = 101;
// Setting with an invalid name should silenty do nothing
// This is done here so if we affect the explicitly set state it will be
// detected soon.
other.Set( GL_TEXTURE0, 0xdead );
// Getting with an invalid name should just return zero
EXPECT_EQ( 0, state.Get( GL_TEXTURE0 ) );
// Peform a swap, so that it is effectively tested too
swap( state, other );
// It should be possible to get the unique value set previously in the
// swapped state.
EXPECT_EQ( 11, state.Get( GL_PACK_SWAP_BYTES ) );
EXPECT_EQ( 12, state.Get( GL_PACK_LSB_FIRST ) );
EXPECT_EQ( 13, state.Get( GL_PACK_ROW_LENGTH ) );
EXPECT_EQ( 14, state.Get( GL_PACK_IMAGE_HEIGHT ) );
EXPECT_EQ( 15, state.Get( GL_PACK_SKIP_ROWS ) );
EXPECT_EQ( 16, state.Get( GL_PACK_SKIP_PIXELS ) );
EXPECT_EQ( 17, state.Get( GL_PACK_SKIP_IMAGES ) );
EXPECT_EQ( 18, state.Get( GL_PACK_ALIGNMENT ) );
EXPECT_EQ( 21, state.Get( GL_UNPACK_SWAP_BYTES ) );
EXPECT_EQ( 22, state.Get( GL_UNPACK_LSB_FIRST ) );
EXPECT_EQ( 23, state.Get( GL_UNPACK_ROW_LENGTH ) );
EXPECT_EQ( 24, state.Get( GL_UNPACK_IMAGE_HEIGHT ) );
EXPECT_EQ( 25, state.Get( GL_UNPACK_SKIP_ROWS ) );
EXPECT_EQ( 26, state.Get( GL_UNPACK_SKIP_PIXELS ) );
EXPECT_EQ( 27, state.Get( GL_UNPACK_SKIP_IMAGES ) );
EXPECT_EQ( 28, state.Get( GL_UNPACK_ALIGNMENT ) );
EXPECT_EQ( 100u, state.pixelPackBufferBinding );
EXPECT_EQ( 101u, state.pixelUnpackBufferBinding );
// Verify the expected default state set previously ended up in the swapped
// state.
EXPECT_EQ( 0, other.Get( GL_PACK_SWAP_BYTES ) );
EXPECT_EQ( 0, other.Get( GL_PACK_LSB_FIRST ) );
EXPECT_EQ( 0, other.Get( GL_PACK_ROW_LENGTH ) );
EXPECT_EQ( 0, other.Get( GL_PACK_IMAGE_HEIGHT ) );
EXPECT_EQ( 0, other.Get( GL_PACK_SKIP_ROWS ) );
EXPECT_EQ( 0, other.Get( GL_PACK_SKIP_PIXELS ) );
EXPECT_EQ( 0, other.Get( GL_PACK_SKIP_IMAGES ) );
EXPECT_EQ( 4, other.Get( GL_PACK_ALIGNMENT ) );
EXPECT_EQ( 0, other.Get( GL_UNPACK_SWAP_BYTES ) );
EXPECT_EQ( 0, other.Get( GL_UNPACK_LSB_FIRST ) );
EXPECT_EQ( 0, other.Get( GL_UNPACK_ROW_LENGTH ) );
EXPECT_EQ( 0, other.Get( GL_UNPACK_IMAGE_HEIGHT ) );
EXPECT_EQ( 0, other.Get( GL_UNPACK_SKIP_ROWS ) );
EXPECT_EQ( 0, other.Get( GL_UNPACK_SKIP_PIXELS ) );
EXPECT_EQ( 0, other.Get( GL_UNPACK_SKIP_IMAGES ) );
EXPECT_EQ( 4, other.Get( GL_UNPACK_ALIGNMENT ) );
EXPECT_EQ( 0u, other.pixelPackBufferBinding );
EXPECT_EQ( 0u, other.pixelUnpackBufferBinding );
}
TEST( RegalClientStatePixelStore, Transition ) {
using ClientState::Capabilities;
using ClientState::PixelStore::State;
using ClientState::PixelStore::PNameToIndex;
using ClientState::PixelStore::Transition;
RegalGMockInterface mock;
Capabilities cap;
DispatchTableGL dt;
::memset(&dt,0,sizeof(DispatchTableGL));
dt._enabled = true;
InitDispatchTableGMock( dt );
State current;
current.Reset();
State target;
target.Reset();
// Set some of the named attributes, and expect that calls will be made
// appropriately to the backend to transition to those value.
target.Set( GL_UNPACK_SKIP_PIXELS, 123 );
target.Set( GL_UNPACK_ALIGNMENT , 456 );
target.pixelPackBufferBinding = 321;
target.pixelUnpackBufferBinding = 654;
EXPECT_CALL( mock, glPixelStorei( GL_UNPACK_SKIP_PIXELS , 123 ) );
EXPECT_CALL( mock, glPixelStorei( GL_UNPACK_ALIGNMENT , 456 ) );
EXPECT_CALL( mock, glBindBuffer ( GL_PIXEL_PACK_BUFFER_BINDING , 321 ) );
EXPECT_CALL( mock, glBindBuffer ( GL_PIXEL_UNPACK_BUFFER_BINDING, 654 ) );
// Perform the state transition
Transition( cap, dt, current, target );
Mock::VerifyAndClear( &mock );
// A transition with no differences should make no calls.
current.Reset();
target.Reset();
target.Set( GL_UNPACK_SKIP_PIXELS, 123 );
target.Set( GL_UNPACK_ALIGNMENT , 456 );
target.pixelPackBufferBinding = 321;
target.pixelUnpackBufferBinding = 654;
current.Set( GL_UNPACK_SKIP_PIXELS, 123 );
current.Set( GL_UNPACK_ALIGNMENT , 456 );
current.pixelPackBufferBinding = 321;
current.pixelUnpackBufferBinding = 654;
// Perform the state transition
Transition( cap, dt, current, target );
Mock::VerifyAndClear( &mock );
}
// ====================================
// ClientState::VertexArray::Fixed::State
// ====================================
TEST( RegalClientStateVertexArrayFixedState, SizesAndMappings ) {
using namespace ClientState::VertexArray::Fixed;
using ClientState::VertexArray::Fixed::State;
using ClientState::VertexArray::Fixed::ArrayNameToAttribIndex;
using ClientState::VertexArray::Fixed::IndexedArrayNameToAttribIndex;
ASSERT_EQ( COUNT_ATTRIBS, arraysize( static_cast<State *>( NULL )->attrib ) );
// An expected attribute name returns the expected index
// (note: the full range of names effectively tested elsewhere)
EXPECT_EQ( BASE_NAMED_ATTRIBS, ArrayNameToAttribIndex( GL_VERTEX_ARRAY ) );
// For most attributes that do not use it, passing in non-default texture unit makes no difference.
EXPECT_EQ( BASE_NAMED_ATTRIBS, ArrayNameToAttribIndex( GL_VERTEX_ARRAY, GL_TEXTURE5 ) );
// An unexpected name should give an invalid index
EXPECT_EQ( INVALID_ATTRIB_INDEX, ArrayNameToAttribIndex( GL_PACK_SWAP_BYTES ) );
EXPECT_EQ( INVALID_ATTRIB_INDEX, ArrayNameToAttribIndex( GL_PACK_SWAP_BYTES, GL_TEXTURE5 ) );
// Texture coordinate attributes do use the texture unit.
EXPECT_EQ( BASE_TEXTURE_COORD_ATTRIBS + 5u, ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE5 ) );
// Passing in a bad texture unit gives an invalid index
EXPECT_EQ( INVALID_ATTRIB_INDEX, ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE0 - 1 ) );
EXPECT_EQ( INVALID_ATTRIB_INDEX, ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE0 + COUNT_TEXTURE_COORD_ATTRIBS ) );
EXPECT_EQ( INVALID_ATTRIB_INDEX, ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, 0 ) );
// Most attribute names are not indexed, and should return an invalid index.
EXPECT_EQ( INVALID_ATTRIB_INDEX, IndexedArrayNameToAttribIndex( GL_VERTEX_ARRAY, 0 ) );
// Unexpected names should also give an invalid index.
EXPECT_EQ( INVALID_ATTRIB_INDEX, IndexedArrayNameToAttribIndex( GL_PACK_SWAP_BYTES, 0 ) );
// Texture coordinates are indexed, and should return valid output indices for valid input indices.
EXPECT_EQ( BASE_TEXTURE_COORD_ATTRIBS, IndexedArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, 0 ) );
EXPECT_EQ( BASE_TEXTURE_COORD_ATTRIBS + COUNT_TEXTURE_COORD_ATTRIBS - 1, IndexedArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, COUNT_TEXTURE_COORD_ATTRIBS - 1 ) );
// But even for texture coordinates, input indices outside the valid range return an invalid index.
EXPECT_EQ( INVALID_ATTRIB_INDEX, IndexedArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, -1 ) );
EXPECT_EQ( INVALID_ATTRIB_INDEX, IndexedArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, COUNT_TEXTURE_COORD_ATTRIBS ) );
}
TEST( RegalClientStateVertexArrayFixedState, BasicOperations ) {
using namespace ClientState::VertexArray::Fixed;
using ClientState::VertexArray::Fixed::State;
using ClientState::VertexArray::Fixed::ArrayNameToAttribIndex;
const size_t normalAttribIndex = ArrayNameToAttribIndex ( GL_NORMAL_ARRAY );
const size_t secondaryColorAttribIndex = ArrayNameToAttribIndex ( GL_SECONDARY_COLOR_ARRAY );
const size_t indexAttribIndex = ArrayNameToAttribIndex ( GL_INDEX_ARRAY );
const size_t fogCoordAttribIndex = ArrayNameToAttribIndex ( GL_FOG_COORD_ARRAY );
const size_t edgeFlagAttribIndex = ArrayNameToAttribIndex ( GL_EDGE_FLAG_ARRAY );
State state;
state.Reset();
State other;
other.Reset();
// Enable a specific attribute array.
state.SetEnable( 4, true );
// Set unique data for the array source for all attributes.
for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
state.SetData( i, i * 10 + 1, i * 10 + 2, i * 10 + 3, i * 10 + 4, i * 10 + 5 );
}
// Calls with out-of-bound values should silently return as a no-op.
// This is done here so if we affect the explicitly set state it will be
// detected soon.
state.SetEnable( INVALID_ATTRIB_INDEX, true );
state.SetEnable( COUNT_ATTRIBS, true );
state.SetData( INVALID_ATTRIB_INDEX, 0xdead, 0xdead, 0xdead, 0xdead, 0xdead );
state.SetData( COUNT_ATTRIBS, 0xdead, 0xdead, 0xdead, 0xdead, 0xdead );
// Peform a swap, so that it is effectively tested too
swap( state, other );
// Verify the unique data that was set is in the swapped state.
for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
const State::Attrib& attrib = other.attrib[ i ];
if ( i == 4 ) {
EXPECT_TRUE( attrib.enabled );
} else {
EXPECT_FALSE( attrib.enabled );
}
EXPECT_EQ( static_cast<GLuint>( i * 10 + 1 ), attrib.source.buffer );
EXPECT_EQ( static_cast<GLint> ( i * 10 + 2 ), attrib.source.size );
EXPECT_EQ( static_cast<GLenum>( i * 10 + 3 ), attrib.source.type );
EXPECT_EQ( static_cast<GLint> ( i * 10 + 4 ), attrib.source.stride );
EXPECT_EQ( static_cast<GLint> ( i * 10 + 5 ), attrib.source.offset );
}
// Verify the expected default state set previously ended up in the swapped
// state.
for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
const State::Attrib& attrib = state.attrib[ i ];
EXPECT_FALSE( attrib.enabled ) << "index " << i;
EXPECT_EQ( 0u, attrib.source.buffer ) << "index " << i;
if ( ( i == indexAttribIndex ) || ( i == fogCoordAttribIndex ) || ( i == edgeFlagAttribIndex ) ) {
EXPECT_EQ( 1, attrib.source.size ) << "index " << i;
} else if ( ( i == secondaryColorAttribIndex ) || ( i == normalAttribIndex ) ) {
EXPECT_EQ( 3, attrib.source.size ) << "index " << i;
} else {
EXPECT_EQ( 4, attrib.source.size ) << "index " << i;
}
if ( i == edgeFlagAttribIndex ) {
EXPECT_EQ( static_cast<GLenum>( GL_BOOL ), attrib.source.type ) << "index " << i;
} else {
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), attrib.source.type ) << "index " << i;
}
EXPECT_EQ( 0, attrib.source.stride ) << "index " << i;
EXPECT_EQ( 0, attrib.source.offset ) << "index " << i;
}
}
TEST( RegalClientStateVertexArrayFixedState, Transition ) {
using ClientState::Capabilities;
using ClientState::VertexArray::Fixed::State;
using ClientState::VertexArray::Fixed::ArrayNameToAttribIndex;
using ClientState::VertexArray::Fixed::IndexedArrayNameToAttribIndex;
using ClientState::VertexArray::Fixed::Transition;
RegalGMockInterface mock;
Capabilities cap;
cap.driverAllowsVertexAttributeArraysWithoutBoundBuffer = true;
DispatchTableGL dt;
::memset(&dt,0,sizeof(DispatchTableGL));
dt._enabled = true;
InitDispatchTableGMock( dt );
State current;
current.Reset();
State target;
target.Reset();
// The mapping between named fixed vertex attributes and the function to set
// their attributes is messy. We explicitly test every one to ensure the
// correct behavior.
// The vertex position attribute array uses all the array state we have.
target.SetEnable ( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), true );
target.SetData ( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), 10, 11, 12, 13, 14 );
EXPECT_CALL( mock, glEnableClientState( GL_VERTEX_ARRAY ) );
EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 10 ) );
EXPECT_CALL( mock, glVertexPointer ( 11, 12, 13, reinterpret_cast<const GLvoid*>( 14 ) ) );
// The vertex normal attribute array does not need the first size argument.
target.SetEnable( ArrayNameToAttribIndex( GL_NORMAL_ARRAY ), true );
target.SetData ( ArrayNameToAttribIndex( GL_NORMAL_ARRAY ), 20, 21, 22, 23, 24 );
EXPECT_CALL( mock, glEnableClientState( GL_NORMAL_ARRAY ) );
EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 20 ) );
EXPECT_CALL( mock, glNormalPointer ( 22, 23, reinterpret_cast<const GLvoid*>( 24 ) ) );
// The color attribute array uses all the array state we have.
target.SetEnable( ArrayNameToAttribIndex( GL_COLOR_ARRAY ), true );
target.SetData ( ArrayNameToAttribIndex( GL_COLOR_ARRAY ), 30, 31, 32, 33, 34 );
EXPECT_CALL( mock, glEnableClientState( GL_COLOR_ARRAY ) );
EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 30 ) );
EXPECT_CALL( mock, glColorPointer ( 31, 32, 33, reinterpret_cast<const GLvoid*>( 34 ) ) );
// The secondary color attribute array uses all the array state we have.
target.SetEnable( ArrayNameToAttribIndex( GL_SECONDARY_COLOR_ARRAY ), true );
target.SetData ( ArrayNameToAttribIndex( GL_SECONDARY_COLOR_ARRAY ), 40, 41, 42, 43, 44 );
EXPECT_CALL( mock, glEnableClientState ( GL_SECONDARY_COLOR_ARRAY ) );
EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 40 ) );
EXPECT_CALL( mock, glSecondaryColorPointer( 41, 42, 43, reinterpret_cast<const GLvoid*>( 44 ) ) );
// The index attribute array does not need the first size argument.
target.SetEnable( ArrayNameToAttribIndex( GL_INDEX_ARRAY ), true );
target.SetData ( ArrayNameToAttribIndex( GL_INDEX_ARRAY ), 50, 51, 52, 53, 54 );
EXPECT_CALL( mock, glEnableClientState( GL_INDEX_ARRAY ) );
EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 50 ) );
EXPECT_CALL( mock, glIndexPointer ( 52, 53, reinterpret_cast<const GLvoid*>( 54 ) ) );
// The edge flag attribute array does not need the size or the type
// arguments.
target.SetEnable( ArrayNameToAttribIndex( GL_EDGE_FLAG_ARRAY ), true );
target.SetData ( ArrayNameToAttribIndex( GL_EDGE_FLAG_ARRAY ), 60, 61, 62, 63, 64 );
EXPECT_CALL( mock, glEnableClientState( GL_EDGE_FLAG_ARRAY ) );
EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 60 ) );
EXPECT_CALL( mock, glEdgeFlagPointer ( 63, reinterpret_cast<const GLvoid*>( 64 ) ) );
// The fog coordiante attribute array does not need the size argument.
target.SetEnable( ArrayNameToAttribIndex( GL_FOG_COORD_ARRAY ), true );
target.SetData ( ArrayNameToAttribIndex( GL_FOG_COORD_ARRAY ), 70, 71, 72, 73, 74 );
EXPECT_CALL( mock, glEnableClientState( GL_FOG_COORD_ARRAY ) );
EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 70 ) );
EXPECT_CALL( mock, glFogCoordPointer ( 72, 73, reinterpret_cast<const GLvoid*>( 74 ) ) );
// There are multiple texture coordinate arrays, one for each texture unit.
// They use all the array state we have.
// They need a call to glClientActiveTexture to select the texture unit, if
// not already seleced.
// Note below we indicate that GL_TEXTURE0 is already selected, so there
// should be no call to select it again.
target.SetEnable( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE0 ), true );
target.SetData ( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE0 ), 80, 81, 82, 83, 84 );
target.SetEnable( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE5 ), true );
target.SetData ( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE5 ), 90, 91, 92, 93, 94 );
EXPECT_CALL( mock, glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ).Times( 2 );
EXPECT_CALL( mock, glClientActiveTexture( GL_TEXTURE5 ) );
EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 80 ) );
EXPECT_CALL( mock, glTexCoordPointer ( 81, 82, 83, reinterpret_cast<const GLvoid*>( 84 ) ) );
EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 90 ) );
EXPECT_CALL( mock, glTexCoordPointer ( 91, 92, 93, reinterpret_cast<const GLvoid*>( 94 ) ) );
// Perform the requested transition
GLenum clientActiveTexture = GL_TEXTURE0;
GLuint arrayBufferBinding = 0;
Transition( cap, dt, current, target, clientActiveTexture, arrayBufferBinding );
// Verify that we've updated the shadowed selected texture unit as expected.
EXPECT_EQ( static_cast<GLenum>( GL_TEXTURE5 ), clientActiveTexture );
EXPECT_EQ( static_cast<GLuint>( 90 ), arrayBufferBinding );
// Verify the call expectations, and reset for another test.
Mock::VerifyAndClear( &mock );
target.Reset();
current.Reset();
// Verify state gets disabled/reset to default from non-default.
current.SetEnable( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), true );
current.SetData ( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), 1, 2, 3, 4, 5 );
current.SetEnable( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE1 ), true );
current.SetData ( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE1 ), 80, 81, 82, 83, 84 );
EXPECT_CALL( mock, glDisableClientState ( GL_VERTEX_ARRAY ) );
EXPECT_CALL( mock, glVertexPointer ( 4, GL_FLOAT, 0, NULL ) );
EXPECT_CALL( mock, glClientActiveTexture( GL_TEXTURE1 ) );
EXPECT_CALL( mock, glDisableClientState ( GL_TEXTURE_COORD_ARRAY ) );
EXPECT_CALL( mock, glTexCoordPointer ( 4, GL_FLOAT, 0, NULL ) );
// Enabling/Disabling an array is a distinct operation.
current.SetEnable( ArrayNameToAttribIndex( GL_NORMAL_ARRAY ), true );
EXPECT_CALL( mock, glDisableClientState( GL_NORMAL_ARRAY ) );
// Setting array data is a distinct operation
current.SetData ( ArrayNameToAttribIndex( GL_COLOR_ARRAY ), 30, 31, 32, 33, 34 );
EXPECT_CALL( mock, glColorPointer ( 4, GL_FLOAT, 0, NULL ) );
// Perform the requested transition
clientActiveTexture = GL_TEXTURE0;
arrayBufferBinding = 0;
Transition( cap, dt, current, target, clientActiveTexture, arrayBufferBinding );
// Verify that we've updated the shadowed selected texture unit as expected.
EXPECT_EQ( static_cast<GLenum>( GL_TEXTURE1 ), clientActiveTexture );
EXPECT_EQ( static_cast<GLuint>( 0 ), arrayBufferBinding );
// Verify the call expectations, and reset for another test.
Mock::VerifyAndClear( &mock );
target.Reset();
current.Reset();
// Identical state is a no-op in terms of calls.
current.SetEnable( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), true );
current.SetData ( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), 1, 2, 3, 4, 5 );
target.SetEnable ( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), true );
target.SetData ( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), 1, 2, 3, 4, 5 );
clientActiveTexture = GL_TEXTURE4;
arrayBufferBinding = 123;
Transition( cap, dt, current, target, clientActiveTexture, arrayBufferBinding );
// Verify that the shadowed selected texture unit is not updated.
EXPECT_EQ( static_cast<GLenum>( GL_TEXTURE4 ), clientActiveTexture );
EXPECT_EQ( static_cast<GLuint>( 123 ), arrayBufferBinding );
// Verify the call expectations, and reset for another test.
Mock::VerifyAndClear( &mock );
target.Reset();
current.Reset();
// If the driver does not support vertex buffer arrays without a bound array
// buffer, then our code should not make the call to set the vertex attribute
// array if the target state use a buffer of zero for that attribute.
cap.driverAllowsVertexAttributeArraysWithoutBoundBuffer = false;
target.SetData ( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), 0, 12, 13, 14, 15 );
target.SetData ( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE1 ), 21, 22, 23, 24, 25 );
EXPECT_CALL( mock, glClientActiveTexture( GL_TEXTURE1 ) );
EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 21 ) );
EXPECT_CALL( mock, glTexCoordPointer ( 22, 23, 24, reinterpret_cast<const void*>( 25 ) ) );
// Perform the requested transition
clientActiveTexture = GL_TEXTURE0;
arrayBufferBinding = 0;
Transition( cap, dt, current, target, clientActiveTexture, arrayBufferBinding );
// Verify the call expectations, and reset for another test.
Mock::VerifyAndClear( &mock );
target.Reset();
current.Reset();
}
// ====================================
// ClientState::VertexArray::Generic::State
// ====================================
TEST( RegalClientStateVertexArrayGenericState, Sizes ) {
using namespace ClientState::VertexArray::Generic;
using ClientState::VertexArray::Generic::State;
ASSERT_EQ( COUNT_ATTRIBS, arraysize( static_cast<State *>( NULL )->attrib ) );
ASSERT_EQ( COUNT_BUFFERS, arraysize( static_cast<State *>( NULL )->buffer ) );
}
TEST( RegalClientStateVertexArrayGenericState, BasicOperations ) {
using namespace ClientState::VertexArray::Generic;
using ClientState::VertexArray::Generic::State;
State state;
state.Reset();
State other;
other.Reset();
// Enable a specific attribute array.
state.SetEnable( 4, true );
// Set unique data for the array source and binding for all attributes.
for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
state.SetAttribSource( i, i * 10 + 1, i * 10 + 2, i == 1, i == 2, i * 10 + 3 );
state.SetAttribBinding( i, ( i + 1 ) % COUNT_BUFFERS );
}
// Set unique data for the array buffers.
for ( size_t i = 0; i < COUNT_BUFFERS; ++i ) {
state.SetBuffer( i, 1000 + i * 10 + 1, 1000 + i * 10 + 2, 1000 + i * 10 + 3 );
state.SetBufferDivisor( i, 1000 + i * 10 + 4 );
}
// Calls with out-of-bound values should silently return as a no-op.
// This is done here so if we affect the explicitly set state it will be
// detected soon.
state.SetEnable( INVALID_INDEX, true );
state.SetEnable( COUNT_ATTRIBS, true );
state.SetAttribSource( INVALID_INDEX, 0xdead, 0xdead, false, false, 0xdead );
state.SetAttribSource( COUNT_ATTRIBS, 0xdead, 0xdead, false, false, 0xdead );
state.SetAttribBinding( INVALID_INDEX, 5 );
state.SetAttribBinding( COUNT_ATTRIBS, 5 );
state.SetAttribBinding( 0, INVALID_INDEX );
state.SetAttribBinding( 0, COUNT_BUFFERS );
state.SetBuffer( INVALID_INDEX, 0xdead, 0xdead, 0xdead );
state.SetBuffer( COUNT_BUFFERS, 0xdead, 0xdead, 0xdead );
state.SetBufferDivisor( INVALID_INDEX, 0xdead );
state.SetBufferDivisor( COUNT_BUFFERS, 0xdead );
// Peform a swap, so that it is effectively tested too.
swap( state, other );
// Verify the unique data that was set is in the swapped state.
for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
const State::Attrib& attrib = other.attrib[ i ];
if ( i == 4 ) {
EXPECT_TRUE( attrib.enabled );
} else {
EXPECT_FALSE( attrib.enabled );
}
EXPECT_EQ( static_cast<GLint> ( i * 10 + 1 ), attrib.source.size );
EXPECT_EQ( static_cast<GLenum>( i * 10 + 2 ), attrib.source.type );
EXPECT_EQ( i * 10 + 3, attrib.source.relativeOffset );
if ( i == 1 ) {
EXPECT_TRUE( attrib.source.normalized );
} else {
EXPECT_FALSE( attrib.source.normalized );
}
if ( i == 2 ) {
EXPECT_TRUE( attrib.source.pureInteger );
} else {
EXPECT_FALSE( attrib.source.pureInteger );
}
EXPECT_EQ( ( i + 1 ) % COUNT_BUFFERS, attrib.bindingIndex );
}
for ( size_t i = 0; i < COUNT_BUFFERS; ++i ) {
const State::Buffer& buffer = other.buffer[ i ];
EXPECT_EQ( 1000 + i * 10 + 1, buffer.buffer );
EXPECT_EQ( static_cast<GLint> ( 1000 + i * 10 + 2 ), buffer.offset );
EXPECT_EQ( static_cast<GLint> ( 1000 + i * 10 + 3 ), buffer.stride );
EXPECT_EQ( 1000 + i * 10 + 4, buffer.divisor );
}
// Verify the expected default state set previously ended up in the swapped
// state.
for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
const State::Attrib& attrib = state.attrib[ i ];
EXPECT_FALSE( attrib.enabled ) << "index " << i;
EXPECT_EQ( 4, attrib.source.size ) << "index " << i;
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), attrib.source.type ) << "index " << i;
EXPECT_EQ( 0u, attrib.source.relativeOffset ) << "index " << i;
EXPECT_FALSE( attrib.source.normalized ) << "index " << i;
EXPECT_FALSE( attrib.source.pureInteger ) << "index " << i;
EXPECT_EQ( i, attrib.bindingIndex ) << "index " << i;
}
for ( size_t i = 0; i < COUNT_BUFFERS; ++i ) {
const State::Buffer& buffer = state.buffer[ i ];
EXPECT_EQ( 0u, buffer.buffer );
EXPECT_EQ( 0, buffer.offset );
EXPECT_EQ( 16, buffer.stride );
EXPECT_EQ( 0u, buffer.divisor );
}
}
TEST( RegalClientStateVertexArrayGenericState, Transition ) {
using ClientState::Capabilities;
using ClientState::VertexArray::Generic::State;
using ClientState::VertexArray::Generic::Transition;
RegalGMockInterface mock;
Capabilities cap;
DispatchTableGL dt;
::memset(&dt,0,sizeof(DispatchTableGL));
dt._enabled = true;
InitDispatchTableGMock( dt );
State current;
current.Reset();
State target;
target.Reset();
// An attribute array can be enabled.
target.SetEnable ( 0, true );
EXPECT_CALL( mock, glEnableVertexAttribArray( 0 ) );
// An attribute array can be configured.
target.SetAttribSource( 1, 11, 12, false, false, 13 );
target.SetAttribSource( 2, 21, 22, true, false, 23 );
target.SetAttribSource( 3, 31, 32, false, true, 33 );
EXPECT_CALL( mock, glVertexAttribFormat ( 1, 11, 12, GL_FALSE, 13 ) );
EXPECT_CALL( mock, glVertexAttribFormat ( 2, 21, 22, GL_TRUE, 23 ) );
EXPECT_CALL( mock, glVertexAttribIFormat( 3, 31, 32, 33 ) );
// An attribute buffer can be configured.
target.SetBuffer( 4, 41, 42, 43 );
EXPECT_CALL( mock, glBindVertexBuffer( 4, 41, 42, 43 ) );
// An attribute buffer divisor can be configured.
target.SetBufferDivisor( 5, 51 );
EXPECT_CALL( mock, glVertexBindingDivisor( 5, 51 ) );
target.SetAttribBinding( 6, 7 );
EXPECT_CALL( mock, glVertexAttribBinding( 6, 7 ) );
// An attribute can be disabled and all data reset to default.
current.SetEnable ( 8, true );
current.SetAttribSource ( 8, 61, 62, false, false, 63 );
current.SetBuffer ( 8, 64, 65, 66 );
current.SetBufferDivisor( 8, 67 );
current.SetAttribBinding( 8, 9 );
EXPECT_CALL( mock, glDisableVertexAttribArray ( 8 ) );
EXPECT_CALL( mock, glVertexAttribFormat ( 8, 4, GL_FLOAT, GL_FALSE, 0 ) );
EXPECT_CALL( mock, glBindVertexBuffer( 8, 0, 0, 16 ) );
EXPECT_CALL( mock, glVertexBindingDivisor( 8, 0 ) );
EXPECT_CALL( mock, glVertexAttribBinding( 8, 8 ) );
// Perform the requested state transition.
Transition( cap, dt, current, target );
// Verify the call expectations, and reset for another test.
Mock::VerifyAndClear( &mock );
target.Reset();
current.Reset();
// Identical state is a no-op in terms of calls.
current.SetEnable ( 0, true );
current.SetAttribSource ( 0, 11, 12, false, false, 13 );
current.SetBuffer ( 0, 14, 15, 16 );
current.SetBufferDivisor( 0, 17 );
current.SetAttribBinding( 0, 1 );
target.SetEnable ( 0, true );
target.SetAttribSource ( 0, 11, 12, false, false, 13 );
target.SetBuffer ( 0, 14, 15, 16 );
target.SetBufferDivisor ( 0, 17 );
target.SetAttribBinding ( 0, 1 );
// Perform the requested state transition.
Transition( cap, dt, current, target );
}
// ====================================
// Regal::ClientState::VertexArray::State
// ====================================
TEST( RegalClientStateVertexArrayState, ResetAndSwap ) {
using ClientState::VertexArray::State;
State state;
state.Reset();
State other;
other.Reset();
state.clientActiveTexture = 1;
state.arrayBufferBinding = 2;
state.drawIndirectBufferBinding = 3;
state.vertexArrayBinding = 4;
state.primitiveRestartEnabled = true;
state.primitiveRestartFixedIndexEnabled = true;
state.primitiveRestartIndex = 5;
state.vertexArrayObjectZero.elementArrayBufferBinding = 6;
swap( state, other );
EXPECT_EQ( static_cast<GLenum>( GL_TEXTURE0 ), state.clientActiveTexture );
EXPECT_EQ( 0u, state.arrayBufferBinding );
EXPECT_EQ( 0u, state.drawIndirectBufferBinding );
EXPECT_EQ( 0u, state.vertexArrayBinding );
EXPECT_FALSE( state.primitiveRestartEnabled );
EXPECT_FALSE( state.primitiveRestartFixedIndexEnabled );
EXPECT_EQ( 0u, state.primitiveRestartIndex );
EXPECT_EQ( 0u, state.vertexArrayObjectZero.elementArrayBufferBinding );
EXPECT_EQ( 1u, other.clientActiveTexture );
EXPECT_EQ( 2u, other.arrayBufferBinding );
EXPECT_EQ( 3u, other.drawIndirectBufferBinding );
EXPECT_EQ( 4u, other.vertexArrayBinding );
EXPECT_TRUE( other.primitiveRestartEnabled );
EXPECT_TRUE( other.primitiveRestartFixedIndexEnabled );
EXPECT_EQ( 5u, other.primitiveRestartIndex );
EXPECT_EQ( 6u, other.vertexArrayObjectZero.elementArrayBufferBinding );
}
TEST( RegalClientStateVertexArrayState, GetVertexArrayObject ) {
using ClientState::VertexArray::State;
State state;
state.Reset();
EXPECT_EQ( &state.vertexArrayObjectZero, state.GetVertexArrayObject( 0 ) );
EXPECT_EQ( NULL, state.GetVertexArrayObject( 1 ) );
state.vertexArrayBinding = 0;
EXPECT_EQ( &state.vertexArrayObjectZero, state.GetVertexArrayObject() );
state.vertexArrayBinding = 1;
EXPECT_EQ( NULL, state.GetVertexArrayObject() );
}
TEST( RegalClientStateVertexArrayState, Transition ) {
using ClientState::Capabilities;
using ClientState::VertexArray::State;
using ClientState::VertexArray::Transition;
RegalGMockInterface mock;
Capabilities cap;
DispatchTableGL dt;
::memset(&dt,0,sizeof(DispatchTableGL));
dt._enabled = true;
InitDispatchTableGMock( dt );
State current;
current.Reset();
State target;
target.Reset();
// Set up a simple non-default state, focusing on state unique this structure.
target.clientActiveTexture = 1;
target.arrayBufferBinding = 2;
target.drawIndirectBufferBinding = 3;
target.vertexArrayBinding = 4;
target.primitiveRestartEnabled = true;
target.primitiveRestartFixedIndexEnabled = true;
target.primitiveRestartIndex = 5;
target.vertexArrayObjectZero.elementArrayBufferBinding = 6;
// Set up expectations.
EXPECT_CALL( mock, glClientActiveTexture( 1 ) );
EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 2 ) );
EXPECT_CALL( mock, glBindBuffer( GL_DRAW_INDIRECT_BUFFER, 3 ) );
EXPECT_CALL( mock, glBindVertexArray( 4 ) );
EXPECT_CALL( mock, glEnable( GL_PRIMITIVE_RESTART ) );
EXPECT_CALL( mock, glEnable( GL_PRIMITIVE_RESTART_FIXED_INDEX ) );
EXPECT_CALL( mock, glPrimitiveRestartIndex( 5 ) );
EXPECT_CALL( mock, glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 6 ) );
// Perform the requested state transition.
Transition( cap, dt, current, target );
// Verify the call expectations, and reset for another test.
Mock::VerifyAndClear( &mock );
// Reverse the transition.
swap( current, target );
// Set up expectations.
EXPECT_CALL( mock, glClientActiveTexture( GL_TEXTURE0 ) );
EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 0 ) );
EXPECT_CALL( mock, glBindBuffer( GL_DRAW_INDIRECT_BUFFER, 0 ) );
EXPECT_CALL( mock, glBindVertexArray( 0 ) );
EXPECT_CALL( mock, glDisable( GL_PRIMITIVE_RESTART ) );
EXPECT_CALL( mock, glDisable( GL_PRIMITIVE_RESTART_FIXED_INDEX ) );
EXPECT_CALL( mock, glPrimitiveRestartIndex( 0 ) );
EXPECT_CALL( mock, glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ) );
// Perform the requested state transition.
Transition( cap, dt, current, target );
// Verify the call expectations, and reset for another test.
Mock::VerifyAndClear( &mock );
}
// ====================================
// Regal::Ppca
// ====================================
TEST ( RegalPpca, ClientPixelStoreStateShadowing ) {
using ClientState::PixelStore::PNameToIndex;
Ppca ppca;
ppca.Reset();
// The value stored should be rounded to the nearest integer.
ppca.ShadowPixelStore( GL_UNPACK_SKIP_PIXELS, 123 );
EXPECT_EQ( 123, ppca.pss.Get( GL_UNPACK_SKIP_PIXELS ) );
ppca.ShadowPixelStore( GL_UNPACK_SKIP_PIXELS, 123 );
EXPECT_EQ( 123, ppca.pss.Get( GL_UNPACK_SKIP_PIXELS ) );
ppca.ShadowPixelStore( GL_UNPACK_SKIP_PIXELS, 123.1f );
EXPECT_EQ( 123, ppca.pss.Get( GL_UNPACK_SKIP_PIXELS ) );
ppca.ShadowPixelStore( GL_UNPACK_SKIP_PIXELS, 123.5f );
EXPECT_EQ( 124, ppca.pss.Get( GL_UNPACK_SKIP_PIXELS ) );
ppca.ShadowPixelStore( GL_UNPACK_SKIP_PIXELS, 123.9f );
EXPECT_EQ( 124, ppca.pss.Get( GL_UNPACK_SKIP_PIXELS ) );
ppca.ShadowPixelStore( GL_UNPACK_SKIP_PIXELS, -123.1f );
EXPECT_EQ( -123, ppca.pss.Get( GL_UNPACK_SKIP_PIXELS ) );
ppca.ShadowPixelStore( GL_UNPACK_SKIP_PIXELS, -123.5f );
EXPECT_EQ( -123, ppca.pss.Get( GL_UNPACK_SKIP_PIXELS ) );
ppca.ShadowPixelStore( GL_UNPACK_SKIP_PIXELS, -123.9f );
EXPECT_EQ( -124, ppca.pss.Get( GL_UNPACK_SKIP_PIXELS ) );
}
TEST ( RegalPpca, ClientVertexArrayStateGenericShadowing ) {
using ClientState::VertexArray::Generic::State;
Ppca ppca;
ppca.Reset();
State& state = ppca.vas.vertexArrayObjectZero.generic;
// VertexAttribFormat
state.Reset();
ppca.ShadowVertexAttribFormat ( 3, 4, GL_FLOAT, GL_TRUE, 123 );
EXPECT_EQ ( 4, state.attrib[ 3 ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ 3 ].source.type );
EXPECT_TRUE ( state.attrib[ 3 ].source.normalized );
EXPECT_FALSE( state.attrib[ 3 ].source.pureInteger );
EXPECT_EQ ( 123u, state.attrib[ 3 ].source.relativeOffset );
state.Reset();
ppca.ShadowVertexAttribFormat ( 3, 4, GL_FLOAT, GL_FALSE, 123 );
EXPECT_FALSE ( state.attrib[ 3 ].source.normalized );
state.Reset();
ppca.ShadowVertexAttribIFormat( 3, 1, GL_INT, 456 );
EXPECT_EQ ( 1, state.attrib[ 3 ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_INT ), state.attrib[ 3 ].source.type );
EXPECT_FALSE( state.attrib[ 3 ].source.normalized );
EXPECT_TRUE ( state.attrib[ 3 ].source.pureInteger );
EXPECT_EQ ( 456u, state.attrib[ 3 ].source.relativeOffset );
state.Reset();
ppca.ShadowVertexAttribLFormat( 3, 2, GL_DOUBLE, 789 );
EXPECT_EQ ( 2, state.attrib[ 3 ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_DOUBLE ), state.attrib[ 3 ].source.type );
EXPECT_FALSE( state.attrib[ 3 ].source.normalized );
EXPECT_FALSE( state.attrib[ 3 ].source.pureInteger );
EXPECT_EQ ( 789u, state.attrib[ 3 ].source.relativeOffset );
// BindVertexBuffer
state.Reset();
ppca.ShadowBindVertexBuffer( 4, 5, 6, 7 );
EXPECT_EQ ( 5u, state.buffer[ 4 ].buffer );
EXPECT_EQ ( static_cast<GLintptr>( 6 ), state.buffer[ 4 ].offset );
EXPECT_EQ ( 7, state.buffer[ 4 ].stride );
EXPECT_EQ ( 0u, state.buffer[ 4 ].divisor );
// VertexAttribBinding
state.Reset();
ppca.ShadowVertexAttribBinding( 3, 4 );
EXPECT_EQ ( 4u, state.attrib[ 3 ].bindingIndex );
// VertexAttribPointer
state.Reset();
ppca.vas.arrayBufferBinding = 8888;
ppca.ShadowVertexAttribPointer ( 3, 1, GL_FLOAT, GL_TRUE, 123, reinterpret_cast<GLvoid *>( 321 ) );
EXPECT_EQ ( 1, state.attrib[ 3 ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ 3 ].source.type );
EXPECT_TRUE ( state.attrib[ 3 ].source.normalized );
EXPECT_FALSE( state.attrib[ 3 ].source.pureInteger );
EXPECT_EQ ( 0u, state.attrib[ 3 ].source.relativeOffset );
EXPECT_EQ ( 3u, state.attrib[ 3 ].bindingIndex );
EXPECT_EQ ( 8888u, state.buffer[ 3 ].buffer );
EXPECT_EQ ( static_cast<GLintptr>( 321 ), state.buffer[ 3 ].offset );
EXPECT_EQ ( 123, state.buffer[ 3 ].stride );
state.Reset();
ppca.ShadowVertexAttribPointer ( 3, 1, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<GLvoid *>( 321 ) );
EXPECT_FALSE( state.attrib[ 3 ].source.normalized );
EXPECT_EQ ( 4, state.buffer[ 3 ].stride );
state.Reset();
ppca.ShadowVertexIAttribPointer( 3, 2, GL_INT, 456, reinterpret_cast<GLvoid *>( 654 ) );
EXPECT_EQ ( 2, state.attrib[ 3 ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_INT ), state.attrib[ 3 ].source.type );
EXPECT_FALSE( state.attrib[ 3 ].source.normalized );
EXPECT_TRUE ( state.attrib[ 3 ].source.pureInteger );
EXPECT_EQ ( 0u, state.attrib[ 3 ].source.relativeOffset );
EXPECT_EQ ( 3u, state.attrib[ 3 ].bindingIndex );
EXPECT_EQ ( 8888u, state.buffer[ 3 ].buffer );
EXPECT_EQ ( static_cast<GLintptr>( 654 ), state.buffer[ 3 ].offset );
EXPECT_EQ ( 456, state.buffer[ 3 ].stride );
state.Reset();
ppca.ShadowVertexIAttribPointer( 3, 2, GL_INT, 0, reinterpret_cast<GLvoid *>( 654 ) );
EXPECT_EQ ( 8, state.buffer[ 3 ].stride );
state.Reset();
ppca.ShadowVertexLAttribPointer( 3, 3, GL_DOUBLE, 789, reinterpret_cast<GLvoid *>( 987 ) );
EXPECT_EQ ( 3, state.attrib[ 3 ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_DOUBLE ), state.attrib[ 3 ].source.type );
EXPECT_FALSE( state.attrib[ 3 ].source.normalized );
EXPECT_FALSE( state.attrib[ 3 ].source.pureInteger );
EXPECT_EQ ( 0u, state.attrib[ 3 ].source.relativeOffset );
EXPECT_EQ ( 3u, state.attrib[ 3 ].bindingIndex );
EXPECT_EQ ( 8888u, state.buffer[ 3 ].buffer );
EXPECT_EQ ( static_cast<GLintptr>( 987 ) , state.buffer[ 3 ].offset );
EXPECT_EQ ( 789, state.buffer[ 3 ].stride );
state.Reset();
ppca.ShadowVertexLAttribPointer( 3, 3, GL_DOUBLE, 0, reinterpret_cast<GLvoid *>( 987 ) );
EXPECT_EQ ( 24, state.buffer[ 3 ].stride );
// Enable/DisableVertexAttribArray
state.Reset();
ppca.ShadowEnableVertexAttribArray( 3 );
EXPECT_TRUE( state.attrib [ 3 ].enabled );
ppca.ShadowDisableVertexAttribArray( 3 );
EXPECT_FALSE( state.attrib [ 3 ].enabled );
// VertexBindingDivisor
state.Reset();
ppca.ShadowVertexBindingDivisor( 4, 123 );
EXPECT_EQ( 123u, state.buffer[ 4 ].divisor );
// VertexAttribDivisor
state.Reset();
ppca.ShadowVertexAttribDivisor( 3, 456 );
EXPECT_EQ( 3u, state.attrib[ 3 ].bindingIndex );
EXPECT_EQ( 456u, state.buffer[ 3 ].divisor );
// ShadowVertexArrayVertexAttribOffsetDSA
state.Reset();
ppca.ShadowVertexArrayVertexAttribOffsetDSA( 0, 987, 3, 1, GL_FLOAT, GL_TRUE, 123, 321 );
EXPECT_EQ ( 1, state.attrib[ 3 ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ 3 ].source.type );
EXPECT_TRUE ( state.attrib[ 3 ].source.normalized );
EXPECT_FALSE( state.attrib[ 3 ].source.pureInteger );
EXPECT_EQ ( 0u, state.attrib[ 3 ].source.relativeOffset );
EXPECT_EQ ( 3u, state.attrib[ 3 ].bindingIndex );
EXPECT_EQ ( 987u, state.buffer[ 3 ].buffer );
EXPECT_EQ ( static_cast<GLintptr>( 321 ), state.buffer[ 3 ].offset );
EXPECT_EQ ( 123, state.buffer[ 3 ].stride );
state.Reset();
ppca.ShadowVertexArrayVertexAttribOffsetDSA( 0, 987, 3, 1, GL_FLOAT, GL_FALSE, 0, 321 );
EXPECT_FALSE ( state.attrib[ 3 ].source.normalized );
EXPECT_EQ ( 4, state.buffer[ 3 ].stride );
state.Reset();
ppca.ShadowVertexArrayVertexAttribIOffsetDSA( 0, 987, 3, 2, GL_INT, 456, 654 );
EXPECT_EQ ( 2, state.attrib[ 3 ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_INT ), state.attrib[ 3 ].source.type );
EXPECT_FALSE( state.attrib[ 3 ].source.normalized );
EXPECT_TRUE ( state.attrib[ 3 ].source.pureInteger );
EXPECT_EQ ( 0u, state.attrib[ 3 ].source.relativeOffset );
EXPECT_EQ ( 3u, state.attrib[ 3 ].bindingIndex );
EXPECT_EQ ( 987u, state.buffer[ 3 ].buffer );
EXPECT_EQ ( static_cast<GLintptr>( 654 ), state.buffer[ 3 ].offset );
EXPECT_EQ ( 456, state.buffer[ 3 ].stride );
state.Reset();
ppca.ShadowVertexArrayVertexAttribIOffsetDSA( 0, 987, 3, 2, GL_INT, 0, 654 );
EXPECT_EQ ( 8, state.buffer[ 3 ].stride );
// EnableDisableVertexArrayAttribDSA
state.Reset();
ppca.ShadowEnableVertexArrayAttribDSA( 0, 3 );
EXPECT_TRUE( state.attrib [ 3 ].enabled );
ppca.ShadowDisableVertexArrayAttribDSA( 0, 3 );
EXPECT_FALSE( state.attrib [ 3 ].enabled );
// If the vertex array binding is nonzero, none of these calls should do
// anything (since we do not actually track internal state for vertex array
// objects.
state.Reset();
state.attrib[ 3 ].source.relativeOffset = 123;
state.attrib[ 3 ].bindingIndex = 4;
state.buffer[ 4 ].buffer = 456;
state.buffer[ 4 ].divisor = 789;
ppca.vas.vertexArrayBinding = 1;
ppca.ShadowVertexAttribFormat ( 3, 3, GL_FLOAT, GL_TRUE, 0 );
ppca.ShadowVertexAttribIFormat( 3, 3, GL_INT, 0 );
ppca.ShadowVertexAttribLFormat( 3, 3, GL_DOUBLE, 0 );
ppca.ShadowBindVertexBuffer( 4, 0, 0, 0 );
ppca.ShadowVertexAttribBinding( 3, 0 );
ppca.ShadowVertexAttribPointer ( 3, 1, GL_FLOAT, GL_TRUE, 0, NULL );
ppca.ShadowVertexIAttribPointer( 3, 2, GL_INT, 0, NULL );
ppca.ShadowVertexLAttribPointer( 3, 3, GL_DOUBLE, 0, NULL );
ppca.ShadowVertexBindingDivisor( 4, 0 );
ppca.ShadowVertexArrayVertexAttribOffsetDSA ( 1, 0, 3, 1, GL_FLOAT, GL_TRUE, 0, 0 );
ppca.ShadowVertexArrayVertexAttribIOffsetDSA( 1, 0, 3, 2, GL_INT, 0, 0 );
EXPECT_EQ ( 123u, state.attrib[ 3 ].source.relativeOffset );
EXPECT_EQ ( 4u, state.attrib[ 3 ].bindingIndex );
EXPECT_EQ ( 456u, state.buffer[ 4 ].buffer );
EXPECT_EQ ( 789u, state.buffer[ 4 ].divisor );
state.attrib [ 3 ].enabled = false;
ppca.ShadowEnableVertexAttribArray( 3 );
ppca.ShadowEnableVertexArrayAttribDSA( 1, 3 );
EXPECT_FALSE( state.attrib [ 3 ].enabled );
state.attrib [ 3 ].enabled = true;
ppca.ShadowDisableVertexAttribArray( 3 );
ppca.ShadowDisableVertexArrayAttribDSA( 1, 3 );
EXPECT_TRUE( state.attrib [ 3 ].enabled );
}
TEST ( RegalPpca, ClientVertexArrayStateFFShadowing ) {
using namespace ClientState::VertexArray::Fixed;
using ClientState::VertexArray::Fixed::State;
using ClientState::VertexArray::Fixed::ArrayNameToAttribIndex;
Ppca ppca;
ppca.Reset();
const size_t colorAttribIndex = ArrayNameToAttribIndex ( GL_COLOR_ARRAY );
const size_t edgeFlagAttribIndex = ArrayNameToAttribIndex ( GL_EDGE_FLAG_ARRAY );
const size_t fogCoordAttribIndex = ArrayNameToAttribIndex ( GL_FOG_COORD_ARRAY );
const size_t indexAttribIndex = ArrayNameToAttribIndex ( GL_INDEX_ARRAY );
const size_t normalAttribIndex = ArrayNameToAttribIndex ( GL_NORMAL_ARRAY );
const size_t secondaryColorAttribIndex = ArrayNameToAttribIndex ( GL_SECONDARY_COLOR_ARRAY );
const size_t vertexAttribIndex = ArrayNameToAttribIndex ( GL_VERTEX_ARRAY );
const size_t texture0AttribIndex = ArrayNameToAttribIndex ( GL_TEXTURE_COORD_ARRAY );
State& state = ppca.vas.vertexArrayObjectZero.fixed;
ppca.ShadowEnableClientState( GL_COLOR_ARRAY );
EXPECT_TRUE( state.attrib[ colorAttribIndex ].enabled );
ppca.ShadowDisableClientState( GL_COLOR_ARRAY );
EXPECT_FALSE( state.attrib[ colorAttribIndex ].enabled );
EXPECT_EQ( static_cast<GLenum>( GL_TEXTURE0 ), ppca.vas.clientActiveTexture );
ppca.ShadowClientActiveTexture( GL_TEXTURE2 );
EXPECT_EQ( static_cast<GLenum>( GL_TEXTURE2 ), ppca.vas.clientActiveTexture );
ppca.ShadowEnableClientState( GL_TEXTURE_COORD_ARRAY );
EXPECT_TRUE( state.attrib[ texture0AttribIndex + 2 ].enabled );
ppca.ShadowDisableClientState( GL_TEXTURE_COORD_ARRAY );
EXPECT_FALSE( state.attrib[ texture0AttribIndex + 2 ].enabled );
ppca.ShadowEnableVertexArrayDSA( 0, GL_TEXTURE_COORD_ARRAY );
EXPECT_TRUE( state.attrib[ texture0AttribIndex + 2 ].enabled );
ppca.ShadowDisableVertexArrayDSA( 0, GL_TEXTURE_COORD_ARRAY );
EXPECT_FALSE( state.attrib[ texture0AttribIndex + 2 ].enabled );
ppca.ShadowEnableVertexArrayDSA( 1, GL_TEXTURE_COORD_ARRAY );
EXPECT_FALSE( state.attrib[ texture0AttribIndex + 2 ].enabled );
ppca.ShadowDisableVertexArrayDSA( 1, GL_TEXTURE_COORD_ARRAY );
EXPECT_FALSE( state.attrib[ texture0AttribIndex + 2 ].enabled );
ppca.ShadowEnableClientStateIndexedDSA( GL_TEXTURE_COORD_ARRAY, 5 );
EXPECT_TRUE( state.attrib[ texture0AttribIndex + 5 ].enabled );
ppca.ShadowDisableClientStateIndexedDSA( GL_TEXTURE_COORD_ARRAY, 5 );
EXPECT_FALSE( state.attrib[ texture0AttribIndex + 5 ].enabled );
for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
state.attrib[ i ].source.buffer = 0;
state.attrib[ i ].source.size = 0;
state.attrib[ i ].source.type = 0;
state.attrib[ i ].source.stride = 0;
}
ppca.vas.arrayBufferBinding = 123;
ppca.ShadowVertexPointer( 4, GL_FLOAT, 1001, NULL );
EXPECT_EQ( 123u, state.attrib[ vertexAttribIndex ].source.buffer );
EXPECT_EQ( 4, state.attrib[ vertexAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ vertexAttribIndex ].source.type );
EXPECT_EQ( 1001, state.attrib[ vertexAttribIndex ].source.stride );
ppca.ShadowNormalPointer( GL_FLOAT, 1002, NULL );
EXPECT_EQ( 123u, state.attrib[ normalAttribIndex ].source.buffer );
EXPECT_EQ( 3, state.attrib[ normalAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ normalAttribIndex ].source.type );
EXPECT_EQ( 1002, state.attrib[ normalAttribIndex ].source.stride );
ppca.ShadowColorPointer( 4, GL_FLOAT, 1003, NULL );
EXPECT_EQ( 123u, state.attrib[ colorAttribIndex ].source.buffer );
EXPECT_EQ( 4, state.attrib[ colorAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex ].source.type );
EXPECT_EQ( 1003, state.attrib[ colorAttribIndex ].source.stride );
ppca.ShadowSecondaryColorPointer( 3, GL_FLOAT, 1004, NULL );
EXPECT_EQ( 123u, state.attrib[ secondaryColorAttribIndex ].source.buffer );
EXPECT_EQ( 3, state.attrib[ secondaryColorAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ secondaryColorAttribIndex ].source.type );
EXPECT_EQ( 1004, state.attrib[ secondaryColorAttribIndex ].source.stride );
ppca.ShadowIndexPointer( GL_INT, 1005, NULL );
EXPECT_EQ( 123u, state.attrib[ indexAttribIndex ].source.buffer );
EXPECT_EQ( 1, state.attrib[ indexAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_INT ), state.attrib[ indexAttribIndex ].source.type );
EXPECT_EQ( 1005, state.attrib[ indexAttribIndex ].source.stride );
ppca.ShadowEdgeFlagPointer( 1006, NULL );
EXPECT_EQ( 123u, state.attrib[ edgeFlagAttribIndex ].source.buffer );
EXPECT_EQ( 1, state.attrib[ edgeFlagAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_BOOL ), state.attrib[ edgeFlagAttribIndex ].source.type );
EXPECT_EQ( 1006, state.attrib[ edgeFlagAttribIndex ].source.stride );
ppca.ShadowFogCoordPointer( GL_FLOAT, 1007, NULL );
EXPECT_EQ( 123u, state.attrib[ fogCoordAttribIndex ].source.buffer );
EXPECT_EQ( 1, state.attrib[ fogCoordAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ fogCoordAttribIndex ].source.type );
EXPECT_EQ( 1007, state.attrib[ fogCoordAttribIndex ].source.stride );
ppca.ShadowTexCoordPointer( 2, GL_FLOAT, 1008, NULL );
EXPECT_EQ( 123u, state.attrib[ texture0AttribIndex + 2 ].source.buffer );
EXPECT_EQ( 2, state.attrib[ texture0AttribIndex + 2 ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ texture0AttribIndex + 2 ].source.type );
EXPECT_EQ( 1008, state.attrib[ texture0AttribIndex + 2 ].source.stride );
ppca.ShadowMultiTexCoordPointerDSA( GL_TEXTURE5, 2, GL_FLOAT, 2005, NULL );
EXPECT_EQ( 123u, state.attrib[ texture0AttribIndex + 5 ].source.buffer );
EXPECT_EQ( 2, state.attrib[ texture0AttribIndex + 5 ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ texture0AttribIndex + 5 ].source.type );
EXPECT_EQ( 2005, state.attrib[ texture0AttribIndex + 5 ].source.stride );
ppca.ShadowVertexArrayVertexOffsetDSA( 0, 3001, 3, GL_FLOAT, 3002, 0 );
EXPECT_EQ( 3001u, state.attrib[ vertexAttribIndex ].source.buffer );
EXPECT_EQ( 3, state.attrib[ vertexAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ vertexAttribIndex ].source.type );
EXPECT_EQ( 3002, state.attrib[ vertexAttribIndex ].source.stride );
ppca.ShadowVertexArrayColorOffsetDSA ( 0, 3003, 4, GL_FLOAT, 3004, 0 );
EXPECT_EQ( 3003u, state.attrib[ colorAttribIndex ].source.buffer );
EXPECT_EQ( 4, state.attrib[ colorAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex ].source.type );
EXPECT_EQ( 3004, state.attrib[ colorAttribIndex ].source.stride );
ppca.ShadowVertexArrayEdgeFlagOffsetDSA ( 0, 3005, 3006, 0 );
EXPECT_EQ( 3005u, state.attrib[ edgeFlagAttribIndex ].source.buffer );
EXPECT_EQ( 1, state.attrib[ edgeFlagAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_BOOL ), state.attrib[ edgeFlagAttribIndex ].source.type );
EXPECT_EQ( 3006, state.attrib[ edgeFlagAttribIndex ].source.stride );
ppca.ShadowVertexArrayIndexOffsetDSA ( 0, 3007, GL_INT, 3008, 0 );
EXPECT_EQ( 3007u, state.attrib[ indexAttribIndex ].source.buffer );
EXPECT_EQ( 1, state.attrib[ indexAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_INT ), state.attrib[ indexAttribIndex ].source.type );
EXPECT_EQ( 3008, state.attrib[ indexAttribIndex ].source.stride );
ppca.ShadowVertexArrayNormalOffsetDSA ( 0, 3009, GL_FLOAT, 3010, 0 );
EXPECT_EQ( 3009u, state.attrib[ normalAttribIndex ].source.buffer );
EXPECT_EQ( 3, state.attrib[ normalAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ normalAttribIndex ].source.type );
EXPECT_EQ( 3010, state.attrib[ normalAttribIndex ].source.stride );
ppca.ShadowVertexArrayTexCoordOffsetDSA( 0, 3011, 2, GL_FLOAT, 3012, 0 );
EXPECT_EQ( 3011u, state.attrib[ texture0AttribIndex + 2 ].source.buffer );
EXPECT_EQ( 2, state.attrib[ texture0AttribIndex + 2 ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ texture0AttribIndex + 2 ].source.type );
EXPECT_EQ( 3012, state.attrib[ texture0AttribIndex + 2 ].source.stride );
ppca.ShadowVertexArrayMultiTexCoordOffsetDSA( 0, 3013, GL_TEXTURE5, 2, GL_FLOAT, 3014, 0 );
EXPECT_EQ( 3013u, state.attrib[ texture0AttribIndex + 5 ].source.buffer );
EXPECT_EQ( 2, state.attrib[ texture0AttribIndex + 5 ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ texture0AttribIndex + 5 ].source.type );
EXPECT_EQ( 3014, state.attrib[ texture0AttribIndex + 5 ].source.stride );
ppca.ShadowVertexArrayFogCoordOffsetDSA ( 0, 3015, GL_FLOAT, 3016, 0 );
EXPECT_EQ( 3015u, state.attrib[ fogCoordAttribIndex ].source.buffer );
EXPECT_EQ( 1, state.attrib[ fogCoordAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ fogCoordAttribIndex ].source.type );
EXPECT_EQ( 3016, state.attrib[ fogCoordAttribIndex ].source.stride );
ppca.ShadowVertexArraySecondaryColorOffsetDSA ( 0, 3017, 3, GL_FLOAT, 3018, 0 );
EXPECT_EQ( 3017u, state.attrib[ secondaryColorAttribIndex ].source.buffer );
EXPECT_EQ( 3, state.attrib[ secondaryColorAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ secondaryColorAttribIndex ].source.type );
EXPECT_EQ( 3018, state.attrib[ secondaryColorAttribIndex ].source.stride );
}
TEST ( RegalPpca, ClientVertexArrayStatePrimitiveRestart ) {
Ppca ppca;
ppca.Reset();
EXPECT_FALSE( ppca.vas.primitiveRestartEnabled );
EXPECT_FALSE( ppca.vas.primitiveRestartFixedIndexEnabled );
EXPECT_EQ( 0u, ppca.vas.primitiveRestartIndex );
ppca.ShadowEnable( GL_PRIMITIVE_RESTART );
EXPECT_TRUE( ppca.vas.primitiveRestartEnabled );
ppca.ShadowDisable( GL_PRIMITIVE_RESTART );
EXPECT_FALSE( ppca.vas.primitiveRestartEnabled );
ppca.ShadowEnable( GL_PRIMITIVE_RESTART_FIXED_INDEX );
EXPECT_TRUE( ppca.vas.primitiveRestartFixedIndexEnabled );
ppca.ShadowDisable( GL_PRIMITIVE_RESTART_FIXED_INDEX );
EXPECT_FALSE( ppca.vas.primitiveRestartFixedIndexEnabled );
ppca.ShadowEnable( GL_TEXTURE_GEN_S );
EXPECT_FALSE( ppca.vas.primitiveRestartEnabled );
EXPECT_FALSE( ppca.vas.primitiveRestartFixedIndexEnabled );
ppca.ShadowDisable( GL_TEXTURE_GEN_S );
ppca.ShadowPrimitiveRestartIndex( ~0u );
EXPECT_EQ( ~0u, ppca.vas.primitiveRestartIndex );
}
TEST ( RegalPpca, ClientVertexArrayStateBindBuffer ) {
using ClientState::VertexArray::Generic::State;
Ppca ppca;
ppca.Reset();
ppca.ShadowBindBuffer( GL_ARRAY_BUFFER, 123 );
ppca.ShadowBindBuffer( GL_DRAW_INDIRECT_BUFFER, 456 );
ppca.ShadowBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 789 );
ppca.ShadowBindBuffer( GL_PIXEL_PACK_BUFFER_BINDING, 321 );
ppca.ShadowBindBuffer( GL_PIXEL_UNPACK_BUFFER_BINDING, 654 );
EXPECT_EQ( 123u, ppca.vas.arrayBufferBinding );
EXPECT_EQ( 456u, ppca.vas.drawIndirectBufferBinding );
EXPECT_EQ( 789u, ppca.vas.vertexArrayObjectZero.elementArrayBufferBinding );
EXPECT_EQ( 321u, ppca.pss.pixelPackBufferBinding );
EXPECT_EQ( 654u, ppca.pss.pixelUnpackBufferBinding );
ppca.Reset();
ppca.vas.vertexArrayBinding = 1;
ppca.ShadowBindBuffer( GL_ARRAY_BUFFER, 123 );
ppca.ShadowBindBuffer( GL_DRAW_INDIRECT_BUFFER, 456 );
ppca.ShadowBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 789 );
ppca.ShadowBindBuffer( GL_PIXEL_PACK_BUFFER_BINDING, 321 );
ppca.ShadowBindBuffer( GL_PIXEL_UNPACK_BUFFER_BINDING, 654 );
EXPECT_EQ( 123u, ppca.vas.arrayBufferBinding );
EXPECT_EQ( 456u, ppca.vas.drawIndirectBufferBinding );
EXPECT_EQ( 0u, ppca.vas.vertexArrayObjectZero.elementArrayBufferBinding );
EXPECT_EQ( 321u, ppca.pss.pixelPackBufferBinding );
EXPECT_EQ( 654u, ppca.pss.pixelUnpackBufferBinding );
}
TEST ( RegalPpca, ClientVertexArrayStateInterleavedArrays ) {
using namespace ClientState::VertexArray::Fixed;
using ClientState::VertexArray::Fixed::State;
using ClientState::VertexArray::Fixed::ArrayNameToAttribIndex;
Ppca ppca;
ppca.Reset();
State& state = ppca.vas.vertexArrayObjectZero.fixed;
const size_t vertexAttribIndex = ArrayNameToAttribIndex ( GL_VERTEX_ARRAY );
const size_t normalAttribIndex = ArrayNameToAttribIndex ( GL_NORMAL_ARRAY );
const size_t colorAttribIndex = ArrayNameToAttribIndex ( GL_COLOR_ARRAY );
const size_t texture0AttribIndex = ArrayNameToAttribIndex ( GL_TEXTURE_COORD_ARRAY );
const size_t edgeFlagAttribIndex = ArrayNameToAttribIndex ( GL_EDGE_FLAG_ARRAY );
const size_t fogCoordAttribIndex = ArrayNameToAttribIndex ( GL_FOG_COORD_ARRAY );
const size_t indexAttribIndex = ArrayNameToAttribIndex ( GL_INDEX_ARRAY );
const size_t secondaryColorAttribIndex = ArrayNameToAttribIndex ( GL_SECONDARY_COLOR_ARRAY );
// Do a comprehensive test on all settings for GL_T4F_C4F_N3F_V4F
state.Reset();
for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
state.attrib[ i ].enabled = ( i & 1 ) == 0;
state.attrib[ i ].source.size = 987;
state.attrib[ i ].source.type = 987;
state.attrib[ i ].source.stride = 987;
state.attrib[ i ].source.offset = 987;
}
ppca.ShadowClientActiveTexture( GL_TEXTURE5 );
ppca.ShadowInterleavedArrays( GL_T4F_C4F_N3F_V4F, 0, NULL );
EXPECT_TRUE ( state.attrib[ vertexAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ normalAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ colorAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ texture0AttribIndex + 5 ].enabled );
EXPECT_EQ( 4, state.attrib[ vertexAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ vertexAttribIndex ].source.type );
EXPECT_EQ( 60, state.attrib[ vertexAttribIndex ].source.stride );
EXPECT_EQ( static_cast<GLintptr>( 44 ), state.attrib[ vertexAttribIndex ].source.offset );
EXPECT_EQ( 3, state.attrib[ normalAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ normalAttribIndex ].source.type );
EXPECT_EQ( 60, state.attrib[ normalAttribIndex ].source.stride );
EXPECT_EQ( static_cast<GLintptr>( 32 ), state.attrib[ normalAttribIndex ].source.offset );
EXPECT_EQ( 4, state.attrib[ colorAttribIndex ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex ].source.type );
EXPECT_EQ( 60, state.attrib[ colorAttribIndex ].source.stride );
EXPECT_EQ( static_cast<GLintptr>( 16 ), state.attrib[ colorAttribIndex ].source.offset );
EXPECT_EQ( 4, state.attrib[ texture0AttribIndex + 5 ].source.size );
EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ texture0AttribIndex + 5 ].source.type );
EXPECT_EQ( 60, state.attrib[ texture0AttribIndex + 5 ].source.stride );
EXPECT_EQ( static_cast<GLintptr>( 0 ), state.attrib[ texture0AttribIndex + 5 ].source.offset );
// The other non-texture coordinate arrays should be disabled
EXPECT_FALSE( state.attrib[ edgeFlagAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ fogCoordAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ indexAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ secondaryColorAttribIndex ].enabled );
// The other non-texture coordinate arrays should not otherwise be touched.
EXPECT_EQ( 987, state.attrib[ edgeFlagAttribIndex ].source.size );
EXPECT_EQ( 987u, state.attrib[ edgeFlagAttribIndex ].source.type );
EXPECT_EQ( 987, state.attrib[ edgeFlagAttribIndex ].source.stride );
EXPECT_EQ( static_cast<GLintptr>( 987 ), state.attrib[ edgeFlagAttribIndex ].source.offset );
EXPECT_EQ( 987, state.attrib[ fogCoordAttribIndex ].source.size );
EXPECT_EQ( 987u, state.attrib[ fogCoordAttribIndex ].source.type );
EXPECT_EQ( 987, state.attrib[ fogCoordAttribIndex ].source.stride );
EXPECT_EQ( static_cast<GLintptr>( 987 ), state.attrib[ fogCoordAttribIndex ].source.offset );
EXPECT_EQ( 987, state.attrib[ indexAttribIndex ].source.size );
EXPECT_EQ( 987u, state.attrib[ indexAttribIndex ].source.type );
EXPECT_EQ( 987, state.attrib[ indexAttribIndex ].source.stride );
EXPECT_EQ( static_cast<GLintptr>( 987 ), state.attrib[ indexAttribIndex ].source.offset );
EXPECT_EQ( 987, state.attrib[ secondaryColorAttribIndex ].source.size );
EXPECT_EQ( 987u, state.attrib[ secondaryColorAttribIndex ].source.type );
EXPECT_EQ( 987, state.attrib[ secondaryColorAttribIndex ].source.stride );
EXPECT_EQ( static_cast<GLintptr>( 987 ), state.attrib[ secondaryColorAttribIndex ].source.offset );
// Verify other texture coordinate settings unaffected.
for ( size_t i = 0; i < COUNT_TEXTURE_COORD_ATTRIBS; ++i ) {
if ( i == 5 ) continue;
State::Attrib& attrib = state.attrib[ BASE_TEXTURE_COORD_ATTRIBS + i ];
if ( ( ( BASE_TEXTURE_COORD_ATTRIBS + i ) & 1 ) == 0 ) {
EXPECT_TRUE( attrib.enabled ) << "Index " << i;
} else {
EXPECT_FALSE( attrib.enabled ) << "Index " << i;
}
EXPECT_EQ( 987, attrib.source.size ) << "Index " << i;
EXPECT_EQ( 987u, attrib.source.type ) << "Index " << i;
EXPECT_EQ( 987, attrib.source.stride ) << "Index " << i;
EXPECT_EQ( static_cast<GLintptr>( 987 ), attrib.source.offset ) << "Index " << i;
}
// Ensure if stride is nonzero, it is used as is, and ensure the pointer passed in is used as a base address.
state.Reset();
ppca.ShadowInterleavedArrays( GL_T4F_C4F_N3F_V4F, 321, reinterpret_cast<GLvoid *>( 5000 ) );
EXPECT_EQ( 321, state.attrib[ vertexAttribIndex ].source.stride );
EXPECT_EQ( static_cast<GLintptr>( 5044 ), state.attrib[ vertexAttribIndex ].source.offset );
EXPECT_EQ( 321, state.attrib[ normalAttribIndex ].source.stride );
EXPECT_EQ( static_cast<GLintptr>( 5032 ), state.attrib[ normalAttribIndex ].source.offset );
EXPECT_EQ( 321, state.attrib[ colorAttribIndex ].source.stride );
EXPECT_EQ( static_cast<GLintptr>( 5016 ), state.attrib[ colorAttribIndex ].source.offset );
EXPECT_EQ( 321, state.attrib[ texture0AttribIndex + 5 ].source.stride );
EXPECT_EQ( static_cast<GLintptr>( 5000 ), state.attrib[ texture0AttribIndex + 5 ].source.offset );
// Do a quick run through the remaining formats, and do some quick verifications.
ppca.Reset();
state.Reset();
ppca.ShadowInterleavedArrays( GL_V2F, 0, NULL );
EXPECT_TRUE ( state.attrib[ vertexAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ normalAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ colorAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ texture0AttribIndex ].enabled );
EXPECT_EQ ( 2, state.attrib[ vertexAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ colorAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ texture0AttribIndex ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex ].source.type );
EXPECT_EQ ( 8, state.attrib[ vertexAttribIndex ].source.stride );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ vertexAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ normalAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ colorAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ texture0AttribIndex ].source.offset );
state.Reset();
ppca.ShadowInterleavedArrays( GL_V3F, 0, NULL );
EXPECT_TRUE ( state.attrib[ vertexAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ normalAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ colorAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ texture0AttribIndex ].enabled );
EXPECT_EQ ( 3, state.attrib[ vertexAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ colorAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ texture0AttribIndex ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex ].source.type );
EXPECT_EQ ( 12, state.attrib[ vertexAttribIndex ].source.stride );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ vertexAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ normalAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ colorAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ texture0AttribIndex ].source.offset );
state.Reset();
ppca.ShadowInterleavedArrays( GL_C4UB_V2F, 0, NULL );
EXPECT_TRUE ( state.attrib[ vertexAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ normalAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ colorAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ texture0AttribIndex ].enabled );
EXPECT_EQ ( 2, state.attrib[ vertexAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ colorAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ texture0AttribIndex ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_UNSIGNED_BYTE ), state.attrib[ colorAttribIndex ].source.type );
EXPECT_EQ ( 12, state.attrib[ vertexAttribIndex ].source.stride );
EXPECT_EQ ( static_cast<GLintptr>( 4 ), state.attrib[ vertexAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ normalAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ colorAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ texture0AttribIndex ].source.offset );
state.Reset();
ppca.ShadowInterleavedArrays( GL_C4UB_V3F, 0, NULL );
EXPECT_TRUE ( state.attrib[ vertexAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ normalAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ colorAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ texture0AttribIndex ].enabled );
EXPECT_EQ ( 3, state.attrib[ vertexAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ colorAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ texture0AttribIndex ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_UNSIGNED_BYTE ), state.attrib[ colorAttribIndex ].source.type );
EXPECT_EQ ( 16, state.attrib[ vertexAttribIndex ].source.stride );
EXPECT_EQ ( static_cast<GLintptr>( 4 ), state.attrib[ vertexAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ normalAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ colorAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ texture0AttribIndex ].source.offset );
state.Reset();
ppca.ShadowInterleavedArrays( GL_C3F_V3F, 0, NULL );
EXPECT_TRUE ( state.attrib[ vertexAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ normalAttribIndex ].enabled );
EXPECT_TRUE( state.attrib[ colorAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ texture0AttribIndex ].enabled );
EXPECT_EQ ( 3, state.attrib[ vertexAttribIndex ].source.size );
EXPECT_EQ ( 3, state.attrib[ colorAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ texture0AttribIndex ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex ].source.type );
EXPECT_EQ ( 24, state.attrib[ vertexAttribIndex ].source.stride );
EXPECT_EQ ( static_cast<GLintptr>( 12 ), state.attrib[ vertexAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ normalAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ colorAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ texture0AttribIndex ].source.offset );
state.Reset();
ppca.ShadowInterleavedArrays( GL_N3F_V3F, 0, NULL );
EXPECT_TRUE ( state.attrib[ vertexAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ normalAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ colorAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ texture0AttribIndex ].enabled );
EXPECT_EQ ( 3, state.attrib[ vertexAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ colorAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ texture0AttribIndex ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex ].source.type );
EXPECT_EQ ( 24, state.attrib[ vertexAttribIndex ].source.stride );
EXPECT_EQ ( static_cast<GLintptr>( 12 ), state.attrib[ vertexAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ normalAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ colorAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ texture0AttribIndex ].source.offset );
state.Reset();
ppca.ShadowInterleavedArrays( GL_C4F_N3F_V3F, 0, NULL );
EXPECT_TRUE ( state.attrib[ vertexAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ normalAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ colorAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ texture0AttribIndex ].enabled );
EXPECT_EQ ( 3, state.attrib[ vertexAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ colorAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ texture0AttribIndex ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex ].source.type );
EXPECT_EQ ( 40, state.attrib[ vertexAttribIndex ].source.stride );
EXPECT_EQ ( static_cast<GLintptr>( 28 ), state.attrib[ vertexAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 16 ), state.attrib[ normalAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ colorAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ texture0AttribIndex ].source.offset );
state.Reset();
ppca.ShadowInterleavedArrays( GL_T2F_V3F, 0, NULL );
EXPECT_TRUE ( state.attrib[ vertexAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ normalAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ colorAttribIndex ].enabled );
EXPECT_TRUE( state.attrib[ texture0AttribIndex ].enabled );
EXPECT_EQ ( 3, state.attrib[ vertexAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ colorAttribIndex ].source.size );
EXPECT_EQ ( 2, state.attrib[ texture0AttribIndex ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex ].source.type );
EXPECT_EQ ( 20, state.attrib[ vertexAttribIndex ].source.stride );
EXPECT_EQ ( static_cast<GLintptr>( 8 ), state.attrib[ vertexAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ normalAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ colorAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ texture0AttribIndex ].source.offset );
state.Reset();
ppca.ShadowInterleavedArrays( GL_T4F_V4F, 0, NULL );
EXPECT_TRUE ( state.attrib[ vertexAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ normalAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ colorAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ texture0AttribIndex ].enabled );
EXPECT_EQ ( 4, state.attrib[ vertexAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ colorAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ texture0AttribIndex ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex ].source.type );
EXPECT_EQ ( 32, state.attrib[ vertexAttribIndex ].source.stride );
EXPECT_EQ ( static_cast<GLintptr>( 16 ), state.attrib[ vertexAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ normalAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ colorAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ texture0AttribIndex ].source.offset );
state.Reset();
ppca.ShadowInterleavedArrays( GL_T2F_C4UB_V3F, 0, NULL );
EXPECT_TRUE ( state.attrib[ vertexAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ normalAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ colorAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ texture0AttribIndex ].enabled );
EXPECT_EQ ( 3, state.attrib[ vertexAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ colorAttribIndex ].source.size );
EXPECT_EQ ( 2, state.attrib[ texture0AttribIndex ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_UNSIGNED_BYTE ), state.attrib[ colorAttribIndex ].source.type );
EXPECT_EQ ( 24, state.attrib[ vertexAttribIndex ].source.stride );
EXPECT_EQ ( static_cast<GLintptr>( 12 ), state.attrib[ vertexAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ normalAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 8 ), state.attrib[ colorAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ texture0AttribIndex ].source.offset );
state.Reset();
ppca.ShadowInterleavedArrays( GL_T2F_C3F_V3F, 0, NULL );
EXPECT_TRUE ( state.attrib[ vertexAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ normalAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ colorAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ texture0AttribIndex ].enabled );
EXPECT_EQ ( 3, state.attrib[ vertexAttribIndex ].source.size );
EXPECT_EQ ( 3, state.attrib[ colorAttribIndex ].source.size );
EXPECT_EQ ( 2, state.attrib[ texture0AttribIndex ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex ].source.type );
EXPECT_EQ ( 32, state.attrib[ vertexAttribIndex ].source.stride );
EXPECT_EQ ( static_cast<GLintptr>( 20 ), state.attrib[ vertexAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ normalAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 8 ), state.attrib[ colorAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ texture0AttribIndex ].source.offset );
state.Reset();
ppca.ShadowInterleavedArrays( GL_T2F_N3F_V3F, 0, NULL );
EXPECT_TRUE ( state.attrib[ vertexAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ normalAttribIndex ].enabled );
EXPECT_FALSE( state.attrib[ colorAttribIndex ].enabled );
EXPECT_TRUE( state.attrib[ texture0AttribIndex ].enabled );
EXPECT_EQ ( 3, state.attrib[ vertexAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ colorAttribIndex ].source.size );
EXPECT_EQ ( 2, state.attrib[ texture0AttribIndex ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex ].source.type );
EXPECT_EQ ( 32, state.attrib[ vertexAttribIndex ].source.stride );
EXPECT_EQ ( static_cast<GLintptr>( 20 ), state.attrib[ vertexAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 8 ), state.attrib[ normalAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ colorAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ texture0AttribIndex ].source.offset );
state.Reset();
ppca.ShadowInterleavedArrays( GL_T2F_C4F_N3F_V3F, 0, NULL );
EXPECT_TRUE ( state.attrib[ vertexAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ normalAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ colorAttribIndex ].enabled );
EXPECT_TRUE ( state.attrib[ texture0AttribIndex ].enabled );
EXPECT_EQ ( 3, state.attrib[ vertexAttribIndex ].source.size );
EXPECT_EQ ( 4, state.attrib[ colorAttribIndex ].source.size );
EXPECT_EQ ( 2, state.attrib[ texture0AttribIndex ].source.size );
EXPECT_EQ ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex ].source.type );
EXPECT_EQ ( 48, state.attrib[ vertexAttribIndex ].source.stride );
EXPECT_EQ ( static_cast<GLintptr>( 36 ), state.attrib[ vertexAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 24 ), state.attrib[ normalAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 8 ), state.attrib[ colorAttribIndex ].source.offset );
EXPECT_EQ ( static_cast<GLintptr>( 0 ), state.attrib[ texture0AttribIndex ].source.offset );
// Pass in an unsupported "format", which should do nothing.
state.Reset();
for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
state.attrib[ i ].enabled = ( i & 1 ) == 0;
state.attrib[ i ].source.size = 987;
state.attrib[ i ].source.type = 987;
state.attrib[ i ].source.stride = 987;
state.attrib[ i ].source.offset = 987;
}
ppca.ShadowInterleavedArrays( GL_RGBA, 0, NULL );
for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
if ( i == 5 ) continue;
State::Attrib& attrib = state.attrib[ i ];
if ( ( i & 1 ) == 0 ) {
EXPECT_TRUE( attrib.enabled ) << "Index " << i;
} else {
EXPECT_FALSE( attrib.enabled ) << "Index " << i;
}
EXPECT_EQ( 987, attrib.source.size ) << "Index " << i;
EXPECT_EQ( 987u, attrib.source.type ) << "Index " << i;
EXPECT_EQ( 987, attrib.source.stride ) << "Index " << i;
EXPECT_EQ( static_cast<GLintptr>( 987 ), attrib.source.offset ) << "Index " << i;
}
}
TEST ( RegalPpca, ShadowDeleteBuffers ) {
Ppca ppca;
ppca.Reset();
GLuint buffers[ 2 ] = { 0, 123 };
for ( size_t i = 0; i < ClientState::VertexArray::Generic::COUNT_BUFFERS; ++i ) {
ppca.vas.vertexArrayObjectZero.generic.buffer[ i ].buffer = 123;
}
ppca.vas.vertexArrayObjectZero.elementArrayBufferBinding = 123;
ppca.vas.arrayBufferBinding = 123;
ppca.vas.drawIndirectBufferBinding = 123;
ppca.pss.pixelPackBufferBinding = 123;
ppca.pss.pixelUnpackBufferBinding = 123;
ppca.ShadowDeleteBuffers( 2, buffers );
for ( size_t i = 0; i < ClientState::VertexArray::Generic::COUNT_BUFFERS; ++i ) {
EXPECT_EQ( 0u, ppca.vas.vertexArrayObjectZero.generic.buffer[ i ].buffer ) << "Index " << i;
}
EXPECT_EQ( 0u, ppca.vas.vertexArrayObjectZero.elementArrayBufferBinding );
EXPECT_EQ( 0u, ppca.vas.arrayBufferBinding );
EXPECT_EQ( 0u, ppca.vas.drawIndirectBufferBinding );
EXPECT_EQ( 0u, ppca.pss.pixelPackBufferBinding );
EXPECT_EQ( 0u, ppca.pss.pixelUnpackBufferBinding );
for ( size_t i = 0; i < ClientState::VertexArray::Generic::COUNT_BUFFERS; ++i ) {
ppca.vas.vertexArrayObjectZero.generic.buffer[ i ].buffer = 456;
}
ppca.vas.vertexArrayObjectZero.elementArrayBufferBinding = 456;
ppca.vas.arrayBufferBinding = 456;
ppca.vas.drawIndirectBufferBinding = 456;
ppca.pss.pixelPackBufferBinding = 456;
ppca.pss.pixelUnpackBufferBinding = 456;
ppca.ShadowDeleteBuffers( 2, buffers );
for ( size_t i = 0; i < ClientState::VertexArray::Generic::COUNT_BUFFERS; ++i ) {
EXPECT_EQ( 456u, ppca.vas.vertexArrayObjectZero.generic.buffer[ i ].buffer ) << "Index " << i;
}
EXPECT_EQ( 456u, ppca.vas.vertexArrayObjectZero.elementArrayBufferBinding );
EXPECT_EQ( 456u, ppca.vas.arrayBufferBinding );
EXPECT_EQ( 456u, ppca.vas.drawIndirectBufferBinding );
EXPECT_EQ( 456u, ppca.pss.pixelPackBufferBinding );
EXPECT_EQ( 456u, ppca.pss.pixelUnpackBufferBinding );
}
TEST ( RegalPpca, ShadowDeleteVertexArrays ) {
Ppca ppca;
ppca.Reset();
GLuint buffers[ 2 ] = { 0, 123 };
ppca.vas.vertexArrayBinding = 123;
ppca.ShadowDeleteVertexArrays( 2, buffers );
EXPECT_EQ( 0u, ppca.vas.vertexArrayBinding );
ppca.vas.vertexArrayBinding = 456;
ppca.ShadowDeleteVertexArrays( 2, buffers );
EXPECT_EQ( 456u, ppca.vas.vertexArrayBinding );
}
TEST ( RegalPpca, ClientAttribStackPixelState ) {
using ClientState::PixelStore::PNameToIndex;
RegalGMockInterface mock;
Ppca ppca;
ppca.Reset();
RegalContext ctx;
ctx.info = new ContextInfo();
InitDispatchTableGMock( ctx.dispatcher.emulation );
EXPECT_EQ( 4, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
EXPECT_EQ( 0u, ppca.pixelStoreStateStack_.size() );
ppca.ShadowPixelStore( GL_UNPACK_ALIGNMENT, 100 );
ppca.PushClientAttrib( &ctx, 0 );
EXPECT_EQ( 100, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
EXPECT_EQ( 0u, ppca.pixelStoreStateStack_.size() );
ppca.ShadowPixelStore( GL_UNPACK_ALIGNMENT, 101 );
ppca.PushClientAttrib( &ctx, GL_CLIENT_PIXEL_STORE_BIT );
EXPECT_EQ( 101, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
EXPECT_EQ( 1u, ppca.pixelStoreStateStack_.size() );
EXPECT_CALL( mock, glPixelStorei( GL_UNPACK_ALIGNMENT, 4 ) );
ppca.ClientAttribDefaultDSA( &ctx, GL_CLIENT_PIXEL_STORE_BIT );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 4, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
EXPECT_EQ( 1u, ppca.pixelStoreStateStack_.size() );
ppca.ShadowPixelStore( GL_UNPACK_ALIGNMENT, 102 );
EXPECT_CALL( mock, glPixelStorei( GL_UNPACK_ALIGNMENT, 4 ) );
ppca.PushClientAttribDefaultDSA( &ctx, GL_CLIENT_PIXEL_STORE_BIT );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 4, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
EXPECT_EQ( 2u, ppca.pixelStoreStateStack_.size() );
EXPECT_CALL( mock, glPixelStorei( GL_UNPACK_ALIGNMENT, 102 ) );
ppca.PopClientAttrib( &ctx );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 102, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
EXPECT_EQ( 1u, ppca.pixelStoreStateStack_.size() );
EXPECT_CALL( mock, glPixelStorei( GL_UNPACK_ALIGNMENT, 101 ) );
ppca.PopClientAttrib( &ctx );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 101, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
EXPECT_EQ( 0u, ppca.pixelStoreStateStack_.size() );
ppca.PopClientAttrib( &ctx );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 101, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
EXPECT_EQ( 0u, ppca.pixelStoreStateStack_.size() );
ppca.PopClientAttrib( &ctx );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 101, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
EXPECT_EQ( 0u, ppca.pixelStoreStateStack_.size() );
}
TEST ( RegalPpca, ClientAttribStackVertexState ) {
using ClientState::VertexArray::Fixed::ArrayNameToAttribIndex;
RegalGMockInterface mock;
Ppca ppca;
ppca.Reset();
RegalContext ctx;
ctx.info = new ContextInfo();
InitDispatchTableGMock( ctx.dispatcher.emulation );
GLint& stride = ppca.vas.vertexArrayObjectZero.fixed.attrib [ ArrayNameToAttribIndex( GL_COLOR_ARRAY ) ].source.stride;
EXPECT_EQ( 0, stride );
EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
ppca.ShadowColorPointer ( 4, GL_FLOAT, 100, NULL );
ppca.PushClientAttrib( &ctx, 0 );
EXPECT_EQ( 100, stride );
EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
ppca.ShadowColorPointer ( 4, GL_FLOAT, 101, NULL );
ppca.PushClientAttrib( &ctx, GL_CLIENT_VERTEX_ARRAY_BIT );
EXPECT_EQ( 101, stride );
EXPECT_EQ( 1u, ppca.vertexArrayStateStack_.size() );
EXPECT_CALL( mock, glColorPointer( 4, GL_FLOAT, 0, NULL ) );
ppca.ClientAttribDefaultDSA( &ctx, GL_CLIENT_VERTEX_ARRAY_BIT );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 0, stride );
EXPECT_EQ( 1u, ppca.vertexArrayStateStack_.size() );
ppca.ShadowColorPointer ( 4, GL_FLOAT, 102, NULL );
EXPECT_CALL( mock, glColorPointer( 4, GL_FLOAT, 0, NULL ) );
ppca.PushClientAttribDefaultDSA( &ctx, GL_CLIENT_VERTEX_ARRAY_BIT );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 0, stride );
EXPECT_EQ( 2u, ppca.vertexArrayStateStack_.size() );
EXPECT_CALL( mock, glColorPointer( 4, GL_FLOAT, 102, NULL ) );
ppca.PopClientAttrib( &ctx );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 102, stride );
EXPECT_EQ( 1u, ppca.vertexArrayStateStack_.size() );
EXPECT_CALL( mock, glColorPointer( 4, GL_FLOAT, 101, NULL ) );
ppca.PopClientAttrib( &ctx );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 101, stride );
EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
ppca.PopClientAttrib( &ctx );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 101, stride );
EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
ppca.PopClientAttrib( &ctx );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 101, stride );
EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
}
TEST ( RegalPpca, ClientAttribStackGeneral ) {
RegalGMockInterface mock;
Ppca ppca;
ppca.Reset();
RegalContext ctx;
ctx.info = new ContextInfo();
ctx.info->core = false;
ctx.info->es2 = false;
InitDispatchTableGMock( ctx.dispatcher.emulation );
const GLbitfield remainder = ~( GL_CLIENT_PIXEL_STORE_BIT | GL_CLIENT_VERTEX_ARRAY_BIT );
EXPECT_EQ( 0u, ppca.pixelStoreStateStack_.size() );
EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
ppca.PushClientAttrib( &ctx, GL_CLIENT_PIXEL_STORE_BIT );
EXPECT_EQ( 1u, ppca.pixelStoreStateStack_.size() );
EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
ppca.PushClientAttrib( &ctx, GL_CLIENT_VERTEX_ARRAY_BIT );
EXPECT_EQ( 1u, ppca.pixelStoreStateStack_.size() );
EXPECT_EQ( 1u, ppca.vertexArrayStateStack_.size() );
EXPECT_CALL( mock, glPushClientAttrib( remainder ) );
ppca.PushClientAttrib( &ctx, GL_CLIENT_ALL_ATTRIB_BITS );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 2u, ppca.pixelStoreStateStack_.size() );
EXPECT_EQ( 2u, ppca.vertexArrayStateStack_.size() );
EXPECT_CALL( mock, glClientAttribDefaultEXT( remainder ) );
ppca.ClientAttribDefaultDSA( &ctx, GL_CLIENT_ALL_ATTRIB_BITS );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 2u, ppca.pixelStoreStateStack_.size() );
EXPECT_EQ( 2u, ppca.vertexArrayStateStack_.size() );
EXPECT_CALL( mock, glClientAttribDefaultEXT( remainder ) );
EXPECT_CALL( mock, glPushClientAttrib( remainder ) );
ppca.PushClientAttribDefaultDSA( &ctx, GL_CLIENT_ALL_ATTRIB_BITS );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 3u, ppca.pixelStoreStateStack_.size() );
EXPECT_EQ( 3u, ppca.vertexArrayStateStack_.size() );
ctx.info->es2 = true;
ppca.PushClientAttrib( &ctx, GL_CLIENT_ALL_ATTRIB_BITS );
ppca.PopClientAttrib( &ctx );
ctx.info->es2 = false;
Mock::VerifyAndClear( &mock );
EXPECT_CALL( mock, glPopClientAttrib() );
ppca.PopClientAttrib( &ctx );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 2u, ppca.pixelStoreStateStack_.size() );
EXPECT_EQ( 2u, ppca.vertexArrayStateStack_.size() );
EXPECT_CALL( mock, glPopClientAttrib() );
ppca.PopClientAttrib( &ctx );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 1u, ppca.pixelStoreStateStack_.size() );
EXPECT_EQ( 1u, ppca.vertexArrayStateStack_.size() );
ppca.PopClientAttrib( &ctx );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 1u, ppca.pixelStoreStateStack_.size() );
EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
ppca.PopClientAttrib( &ctx );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 0u, ppca.pixelStoreStateStack_.size() );
EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
ppca.PopClientAttrib( &ctx );
Mock::VerifyAndClear( &mock );
EXPECT_EQ( 0u, ppca.pixelStoreStateStack_.size() );
EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
}
TEST ( RegalPpca, Get ) {
Ppca ppca;
ppca.Reset();
RegalContext ctx;
ctx.info = new ContextInfo();
ctx.info->es2 = true;
GLint resulti[ 1 ] = { 123 };
GLint64 resulti64[ 1 ] = { 123 };
GLfloat resultf[ 1 ] = { 123.f };
GLdouble resultd[ 1 ] = { 123. };
GLboolean resultb[ 1 ] = { GL_FALSE };
// First ensure getting an unimplemented value works (does nothing).
EXPECT_FALSE( ppca.Get( &ctx, GL_FLOAT, resulti ) );
EXPECT_EQ( 123, resulti[ 0 ] );
EXPECT_FALSE( ppca.Get( &ctx, GL_FLOAT, resulti64 ) );
EXPECT_EQ( 123, resulti64[ 0 ] );
EXPECT_FALSE( ppca.Get( &ctx, GL_FLOAT, resultf ) );
EXPECT_EQ( 123, resultf[ 0 ] );
EXPECT_FALSE( ppca.Get( &ctx, GL_FLOAT, resultd ) );
EXPECT_EQ( 123, resultd[ 0 ] );
EXPECT_FALSE( ppca.Get( &ctx, GL_FLOAT, resultb ) );
EXPECT_EQ( GL_FALSE, resultb[ 0 ] );
// Next verify that getting an implemented value gets the value.
EXPECT_TRUE( ppca.Get( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resulti ) );
EXPECT_EQ( REGAL_PPCA_MAX_CLIENT_ATTRIB_STACK_DEPTH, resulti[ 0 ] );
EXPECT_TRUE( ppca.Get( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resulti64 ) );
EXPECT_EQ( REGAL_PPCA_MAX_CLIENT_ATTRIB_STACK_DEPTH, resulti64[ 0 ] );
EXPECT_TRUE( ppca.Get( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resultf ) );
EXPECT_EQ( REGAL_PPCA_MAX_CLIENT_ATTRIB_STACK_DEPTH, resultf[ 0 ] );
EXPECT_TRUE( ppca.Get( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resultd ) );
EXPECT_EQ( REGAL_PPCA_MAX_CLIENT_ATTRIB_STACK_DEPTH, resultd[ 0 ] );
EXPECT_TRUE( ppca.Get( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resultb ) );
EXPECT_EQ( GL_TRUE, resultb[ 0 ] );
// If the backend appears to be compatible with the request, the emulation
// should just defer to the backend.
ctx.info->es2 = ctx.info->core = false;
EXPECT_FALSE( ppca.Get( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resulti ) );
}
} // namespace