From ab3d48947a75262fdf950c4078f3e6886328ce6c Mon Sep 17 00:00:00 2001 From: rogerman Date: Fri, 18 Jan 2019 13:54:37 -0800 Subject: [PATCH] OpenGL Renderer: Reduce some buffer related synchronization in BeginRender(). --- desmume/src/OGLRender.cpp | 65 ++++++++++----------------- desmume/src/OGLRender.h | 2 +- desmume/src/OGLRender_3_2.cpp | 85 +++++++++++++++++------------------ desmume/src/OGLRender_3_2.h | 1 + desmume/src/wifi.h | 38 +++++++++++----- 5 files changed, 93 insertions(+), 98 deletions(-) diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 9130a142a..8f7eb844c 100755 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -2394,9 +2394,6 @@ OpenGLRenderer_1_2::~OpenGLRenderer_1_2() delete[] ref->color4fBuffer; ref->color4fBuffer = NULL; - delete[] ref->vertIndexBuffer; - ref->vertIndexBuffer = NULL; - if (this->isShaderSupported) { glUseProgram(0); @@ -2697,7 +2694,7 @@ Render3DError OpenGLRenderer_1_2::CreateVBOs() glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID); glBufferDataARB(GL_ARRAY_BUFFER_ARB, VERTLIST_SIZE * sizeof(VERT), NULL, GL_STREAM_DRAW_ARB); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboGeometryIndexID); - glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRENDER_VERT_INDEX_BUFFER_COUNT * sizeof(GLushort), NULL, GL_STREAM_DRAW_ARB); + glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(OGLRef.vertIndexBuffer), NULL, GL_STREAM_DRAW_ARB); glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboPostprocessVtxID); glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(PostprocessVtxBuffer), PostprocessVtxBuffer, GL_STATIC_DRAW_ARB); @@ -3745,10 +3742,6 @@ Render3DError OpenGLRenderer_1_2::InitFinalRenderStates(const std::setisShaderSupported) ? NULL : new GLfloat[VERTLIST_SIZE * 4]; - // If VBOs aren't supported, then we need to create the index buffer on the - // client side so that we have a buffer to update. - OGLRef.vertIndexBuffer = (this->isVBOSupported) ? NULL : new GLushort[OGLRENDER_VERT_INDEX_BUFFER_COUNT]; - return OGLERROR_NOERR; } @@ -4243,13 +4236,13 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine) return OGLERROR_BEGINGL_FAILED; } - GLushort *indexPtr = NULL; - if (this->isVBOSupported) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboGeometryIndexID); - indexPtr = (GLushort *)glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + + // Only copy as much vertex data as we need to, since this can be a potentially large upload size. + glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(VERT) * engine.vertListCount, engine.vertList); } else { @@ -4257,13 +4250,10 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine) OGLRef.vtxPtrPosition = &engine.vertList[0].coord; OGLRef.vtxPtrTexCoord = &engine.vertList[0].texcoord; OGLRef.vtxPtrColor = (this->isShaderSupported) ? (GLvoid *)&engine.vertList[0].color : OGLRef.color4fBuffer; - indexPtr = OGLRef.vertIndexBuffer; } this->_renderNeedsDepthEqualsTest = false; - size_t vertIndexCount = 0; - - for (size_t i = 0; i < engine.polylist->count; i++) + for (size_t i = 0, vertIndexCount = 0; i < engine.polylist->count; i++) { const POLY &thePoly = engine.polylist->list[engine.indexlist.list[i]]; const size_t polyType = thePoly.type; @@ -4284,16 +4274,16 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine) // a buffer. For GFX3D_QUADS and GFX3D_QUAD_STRIP, we also add additional // vertices here to convert them to GL_TRIANGLES, which are much easier // to work with and won't be deprecated in future OpenGL versions. - indexPtr[vertIndexCount++] = vertIndex; + OGLRef.vertIndexBuffer[vertIndexCount++] = vertIndex; if (!thePoly.isWireframe() && (thePoly.vtxFormat == GFX3D_QUADS || thePoly.vtxFormat == GFX3D_QUAD_STRIP)) { if (j == 2) { - indexPtr[vertIndexCount++] = vertIndex; + OGLRef.vertIndexBuffer[vertIndexCount++] = vertIndex; } else if (j == 3) { - indexPtr[vertIndexCount++] = thePoly.vertIndexes[0]; + OGLRef.vertIndexBuffer[vertIndexCount++] = thePoly.vertIndexes[0]; } } } @@ -4319,16 +4309,16 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine) // buffer. For GFX3D_QUADS and GFX3D_QUAD_STRIP, we also add additional // vertices here to convert them to GL_TRIANGLES, which are much easier // to work with and won't be deprecated in future OpenGL versions. - indexPtr[vertIndexCount++] = vertIndex; + OGLRef.vertIndexBuffer[vertIndexCount++] = vertIndex; if (!thePoly.isWireframe() && (thePoly.vtxFormat == GFX3D_QUADS || thePoly.vtxFormat == GFX3D_QUAD_STRIP)) { if (j == 2) { - indexPtr[vertIndexCount++] = vertIndex; + OGLRef.vertIndexBuffer[vertIndexCount++] = vertIndex; } else if (j == 3) { - indexPtr[vertIndexCount++] = thePoly.vertIndexes[0]; + OGLRef.vertIndexBuffer[vertIndexCount++] = thePoly.vertIndexes[0]; } } } @@ -4377,8 +4367,9 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine) if (this->isVBOSupported) { - glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); - glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(VERT) * engine.vertListCount, engine.vertList); + // Replace the entire index buffer as a hint to the driver that we can orphan the index buffer and + // avoid a synchronization cost. + glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(OGLRef.vertIndexBuffer), OGLRef.vertIndexBuffer); } if (this->isShaderSupported) @@ -5262,11 +5253,6 @@ Render3DError OpenGLRenderer_1_2::Reset() memset(OGLRef.color4fBuffer, 0, VERTLIST_SIZE * 4 * sizeof(GLfloat)); } - if (OGLRef.vertIndexBuffer != NULL) - { - memset(OGLRef.vertIndexBuffer, 0, OGLRENDER_VERT_INDEX_BUFFER_COUNT * sizeof(GLushort)); - } - this->_renderNeedsDepthEqualsTest = false; this->_currentPolyIndex = 0; @@ -5514,9 +5500,6 @@ Render3DError OpenGLRenderer_2_0::InitFinalRenderStates(const std::set_renderNeedsDepthEqualsTest = false; - - size_t vertIndexCount = 0; - GLushort *indexPtr = (GLushort *)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY); - - for (size_t i = 0; i < engine.polylist->count; i++) + for (size_t i = 0, vertIndexCount = 0; i < engine.polylist->count; i++) { const POLY &thePoly = engine.polylist->list[engine.indexlist.list[i]]; const size_t polyType = thePoly.type; @@ -5593,16 +5575,16 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D &engine) // a buffer. For GFX3D_QUADS and GFX3D_QUAD_STRIP, we also add additional // vertices here to convert them to GL_TRIANGLES, which are much easier // to work with and won't be deprecated in future OpenGL versions. - indexPtr[vertIndexCount++] = vertIndex; + OGLRef.vertIndexBuffer[vertIndexCount++] = vertIndex; if (!thePoly.isWireframe() && (thePoly.vtxFormat == GFX3D_QUADS || thePoly.vtxFormat == GFX3D_QUAD_STRIP)) { if (j == 2) { - indexPtr[vertIndexCount++] = vertIndex; + OGLRef.vertIndexBuffer[vertIndexCount++] = vertIndex; } else if (j == 3) { - indexPtr[vertIndexCount++] = thePoly.vertIndexes[0]; + OGLRef.vertIndexBuffer[vertIndexCount++] = thePoly.vertIndexes[0]; } } } @@ -5648,8 +5630,9 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D &engine) } } - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(VERT) * engine.vertListCount, engine.vertList); + // Replace the entire index buffer as a hint to the driver that we can orphan the index buffer and + // avoid a synchronization cost. + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(OGLRef.vertIndexBuffer), OGLRef.vertIndexBuffer); // Setup render states this->_geometryProgramFlags.EnableWDepth = (engine.renderState.wbuffer) ? 1 : 0; diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index e548da866..db951a564 100755 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -569,7 +569,7 @@ struct OGLRenderRef // Client-side Buffers GLfloat *color4fBuffer; - GLushort *vertIndexBuffer; + CACHE_ALIGN GLushort vertIndexBuffer[OGLRENDER_VERT_INDEX_BUFFER_COUNT]; CACHE_ALIGN GLushort workingCIColorBuffer[GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; CACHE_ALIGN GLuint workingCIDepthStencilBuffer[2][GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; CACHE_ALIGN GLuint workingCIFogAttributesBuffer[2][GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index d00643164..6ae3b1939 100755 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -1401,7 +1401,6 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms() glGenBuffers(1, &OGLRef.tboPolyStatesID); glBindBuffer(GL_TEXTURE_BUFFER, OGLRef.tboPolyStatesID); glBufferData(GL_TEXTURE_BUFFER, POLYLIST_SIZE * sizeof(OGLPolyStates), NULL, GL_DYNAMIC_DRAW); - glBindBuffer(GL_TEXTURE_BUFFER, 0); glGenTextures(1, &OGLRef.texPolyStatesID); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_PolyStates); @@ -2107,63 +2106,65 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D &engine) return OGLERROR_BEGINGL_FAILED; } - glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_PolyStates); glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID); - glBindBuffer(GL_TEXTURE_BUFFER, OGLRef.tboPolyStatesID); - glBindBuffer(GL_UNIFORM_BUFFER, OGLRef.uboRenderStatesID); - // Copy the vertex data. + // Copy the vertex data to the GPU asynchronously due to the potentially large upload size. + // This buffer write will need to be synchronized before we start drawing. + if (this->_syncBufferSetup != NULL) + { + glWaitSync(this->_syncBufferSetup, 0, GL_TIMEOUT_IGNORED); + glDeleteSync(this->_syncBufferSetup); + } + const size_t vtxBufferSize = sizeof(VERT) * engine.vertListCount; VERT *vtxPtr = (VERT *)glMapBufferRange(GL_ARRAY_BUFFER, 0, vtxBufferSize, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); memcpy(vtxPtr, engine.vertList, vtxBufferSize); glUnmapBuffer(GL_ARRAY_BUFFER); - // Set up rendering states that will remain constant for the entire frame. - OGLRenderStates *state = (OGLRenderStates *)glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(OGLRenderStates), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); + this->_syncBufferSetup = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - state->enableAntialiasing = (engine.renderState.enableAntialiasing) ? GL_TRUE : GL_FALSE; - state->enableFogAlphaOnly = (engine.renderState.enableFogAlphaOnly) ? GL_TRUE : GL_FALSE; - state->clearPolyID = this->_clearAttributes.opaquePolyID; - state->clearDepth = (GLfloat)this->_clearAttributes.depth / (GLfloat)0x00FFFFFF; - state->alphaTestRef = divide5bitBy31_LUT[engine.renderState.alphaTestRef]; - state->fogColor.r = divide5bitBy31_LUT[(engine.renderState.fogColor ) & 0x0000001F]; - state->fogColor.g = divide5bitBy31_LUT[(engine.renderState.fogColor >> 5) & 0x0000001F]; - state->fogColor.b = divide5bitBy31_LUT[(engine.renderState.fogColor >> 10) & 0x0000001F]; - state->fogColor.a = divide5bitBy31_LUT[(engine.renderState.fogColor >> 16) & 0x0000001F]; - state->fogOffset = (GLfloat)(engine.renderState.fogOffset & 0x7FFF) / 32767.0f; - state->fogStep = (GLfloat)(0x0400 >> engine.renderState.fogShift) / 32767.0f; + // Set up rendering states that will remain constant for the entire frame. + this->_pendingRenderStates.enableAntialiasing = (engine.renderState.enableAntialiasing) ? GL_TRUE : GL_FALSE; + this->_pendingRenderStates.enableFogAlphaOnly = (engine.renderState.enableFogAlphaOnly) ? GL_TRUE : GL_FALSE; + this->_pendingRenderStates.clearPolyID = this->_clearAttributes.opaquePolyID; + this->_pendingRenderStates.clearDepth = (GLfloat)this->_clearAttributes.depth / (GLfloat)0x00FFFFFF; + this->_pendingRenderStates.alphaTestRef = divide5bitBy31_LUT[engine.renderState.alphaTestRef]; + this->_pendingRenderStates.fogColor.r = divide5bitBy31_LUT[(engine.renderState.fogColor ) & 0x0000001F]; + this->_pendingRenderStates.fogColor.g = divide5bitBy31_LUT[(engine.renderState.fogColor >> 5) & 0x0000001F]; + this->_pendingRenderStates.fogColor.b = divide5bitBy31_LUT[(engine.renderState.fogColor >> 10) & 0x0000001F]; + this->_pendingRenderStates.fogColor.a = divide5bitBy31_LUT[(engine.renderState.fogColor >> 16) & 0x0000001F]; + this->_pendingRenderStates.fogOffset = (GLfloat)(engine.renderState.fogOffset & 0x7FFF) / 32767.0f; + this->_pendingRenderStates.fogStep = (GLfloat)(0x0400 >> engine.renderState.fogShift) / 32767.0f; for (size_t i = 0; i < 32; i++) { - state->fogDensity[i].r = (engine.renderState.fogDensityTable[i] == 127) ? 1.0f : (GLfloat)engine.renderState.fogDensityTable[i] / 128.0f; - state->fogDensity[i].g = 0.0f; - state->fogDensity[i].b = 0.0f; - state->fogDensity[i].a = 0.0f; + this->_pendingRenderStates.fogDensity[i].r = (engine.renderState.fogDensityTable[i] == 127) ? 1.0f : (GLfloat)engine.renderState.fogDensityTable[i] / 128.0f; + this->_pendingRenderStates.fogDensity[i].g = 0.0f; + this->_pendingRenderStates.fogDensity[i].b = 0.0f; + this->_pendingRenderStates.fogDensity[i].a = 0.0f; } const GLfloat edgeColorAlpha = (engine.renderState.enableAntialiasing) ? (16.0f/31.0f) : 1.0f; for (size_t i = 0; i < 8; i++) { - state->edgeColor[i].r = divide5bitBy31_LUT[(engine.renderState.edgeMarkColorTable[i] ) & 0x001F]; - state->edgeColor[i].g = divide5bitBy31_LUT[(engine.renderState.edgeMarkColorTable[i] >> 5) & 0x001F]; - state->edgeColor[i].b = divide5bitBy31_LUT[(engine.renderState.edgeMarkColorTable[i] >> 10) & 0x001F]; - state->edgeColor[i].a = edgeColorAlpha; + this->_pendingRenderStates.edgeColor[i].r = divide5bitBy31_LUT[(engine.renderState.edgeMarkColorTable[i] ) & 0x001F]; + this->_pendingRenderStates.edgeColor[i].g = divide5bitBy31_LUT[(engine.renderState.edgeMarkColorTable[i] >> 5) & 0x001F]; + this->_pendingRenderStates.edgeColor[i].b = divide5bitBy31_LUT[(engine.renderState.edgeMarkColorTable[i] >> 10) & 0x001F]; + this->_pendingRenderStates.edgeColor[i].a = edgeColorAlpha; } for (size_t i = 0; i < 32; i++) { - state->toonColor[i].r = divide5bitBy31_LUT[(engine.renderState.u16ToonTable[i] ) & 0x001F]; - state->toonColor[i].g = divide5bitBy31_LUT[(engine.renderState.u16ToonTable[i] >> 5) & 0x001F]; - state->toonColor[i].b = divide5bitBy31_LUT[(engine.renderState.u16ToonTable[i] >> 10) & 0x001F]; - state->toonColor[i].a = 1.0f; + this->_pendingRenderStates.toonColor[i].r = divide5bitBy31_LUT[(engine.renderState.u16ToonTable[i] ) & 0x001F]; + this->_pendingRenderStates.toonColor[i].g = divide5bitBy31_LUT[(engine.renderState.u16ToonTable[i] >> 5) & 0x001F]; + this->_pendingRenderStates.toonColor[i].b = divide5bitBy31_LUT[(engine.renderState.u16ToonTable[i] >> 10) & 0x001F]; + this->_pendingRenderStates.toonColor[i].a = 1.0f; } - glUnmapBuffer(GL_UNIFORM_BUFFER); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(this->_pendingRenderStates), &this->_pendingRenderStates); // Set up the polygon states. - GLushort *indexPtr = (GLushort *)glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, engine.polylist->count * 6 * sizeof(GLushort), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); - this->_renderNeedsDepthEqualsTest = false; for (size_t i = 0, vertIndexCount = 0; i < engine.polylist->count; i++) { @@ -2184,16 +2185,16 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D &engine) // a buffer. For GFX3D_QUADS and GFX3D_QUAD_STRIP, we also add additional // vertices here to convert them to GL_TRIANGLES, which are much easier // to work with and won't be deprecated in future OpenGL versions. - indexPtr[vertIndexCount++] = vertIndex; + OGLRef.vertIndexBuffer[vertIndexCount++] = vertIndex; if (!thePoly.isWireframe() && (thePoly.vtxFormat == GFX3D_QUADS || thePoly.vtxFormat == GFX3D_QUAD_STRIP)) { if (j == 2) { - indexPtr[vertIndexCount++] = vertIndex; + OGLRef.vertIndexBuffer[vertIndexCount++] = vertIndex; } else if (j == 3) { - indexPtr[vertIndexCount++] = thePoly.vertIndexes[0]; + OGLRef.vertIndexBuffer[vertIndexCount++] = thePoly.vertIndexes[0]; } } } @@ -2238,16 +2239,10 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D &engine) this->_willForceTextureSampleClampT[i] = this->_willForceTextureSampleClampT[i] && ( ((tc[3].y > -0.0001f) && (tc[3].y < 0.0001f)) || ((tc[3].y > 0.9999f) && (tc[3].y < 1.0001f)) ); } } - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); - // Since we used GL_MAP_UNSYNCHRONIZED_BIT with the previous buffers, - // we will need to synchronize the buffer writes before we start drawing. - if (this->_syncBufferSetup != NULL) - { - glWaitSync(this->_syncBufferSetup, 0, GL_TIMEOUT_IGNORED); - glDeleteSync(this->_syncBufferSetup); - } - this->_syncBufferSetup = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + // Replace the entire index buffer as a hint to the driver that we can orphan the index buffer and + // avoid a synchronization cost. + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(OGLRef.vertIndexBuffer), OGLRef.vertIndexBuffer); // Some drivers seem to have problems with glMapBufferRange() and GL_TEXTURE_BUFFER, causing // certain polygons to intermittently flicker in certain games. Therefore, we'll use glMapBuffer() diff --git a/desmume/src/OGLRender_3_2.h b/desmume/src/OGLRender_3_2.h index ca5a14bc3..fc64dadcf 100644 --- a/desmume/src/OGLRender_3_2.h +++ b/desmume/src/OGLRender_3_2.h @@ -63,6 +63,7 @@ class OpenGLRenderer_3_2 : public OpenGLRenderer_2_1 { protected: GLsync _syncBufferSetup; + CACHE_ALIGN OGLRenderStates _pendingRenderStates; virtual Render3DError InitExtensions(); diff --git a/desmume/src/wifi.h b/desmume/src/wifi.h index 901b59228..756612329 100755 --- a/desmume/src/wifi.h +++ b/desmume/src/wifi.h @@ -3098,6 +3098,20 @@ typedef struct }; } IPv4Header; + + +// The maximum possible size of any 802.11 frame is 2346 bytes: +// - Max MTU is 2304 bytes +// - Max 802.11 header size is 30 bytes +// - WEP Encryption Header size is 8 bytes +// - FCS size is 4 bytes +#define MAX_PACKET_SIZE_80211 2346 + +// Given a connection of 2 megabits per second, we take ~4 microseconds to transfer a byte. +// This works out to needing ~8 microseconds to transfer a halfword. +#define TX_LATENCY_LIMIT 8 +#define RX_LATENCY_LIMIT 8 + // NDS Frame Header Information typedef struct { @@ -3111,6 +3125,19 @@ typedef struct u16 length; // Total length of header+body+checksum, in bytes. } TXPacketHeader; +typedef union +{ + u8 rawFrameData[sizeof(TXPacketHeader) + MAX_PACKET_SIZE_80211 + sizeof(u16) + sizeof(u16)]; + + struct + { + TXPacketHeader txHeader; + u8 txData[MAX_PACKET_SIZE_80211]; + u16 remainingBytes; + u16 latencyCount; + }; +} TXBufferedPacket; + typedef union { u16 value; @@ -3139,17 +3166,6 @@ typedef struct u8 rssiMin; } RXPacketHeader; -// The maximum possible size of any 802.11 frame is 2346 bytes: -// - Max MTU is 2304 bytes -// - Max 802.11 header size is 30 bytes -// - WEP Encryption Header size is 8 bytes -// - FCS size is 4 bytes -#define MAX_PACKET_SIZE_80211 2346 - -// Given a connection of 2 megabits per second, we take ~4 microseconds to transfer a byte. -// This works out to needing ~8 microseconds to transfer a halfword. -#define RX_LATENCY_LIMIT 8 - typedef union { u8 rawFrameData[sizeof(RXPacketHeader) + MAX_PACKET_SIZE_80211 + sizeof(u16)];