diff --git a/src/external/rlsw.h b/src/external/rlsw.h index a48ca70a1..3324f969c 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -844,6 +844,17 @@ SWAPI void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWatta #endif #endif +// ESP-DSP acceleration: ESP-IDF ships an optimized math library that includes +// `dspm_mult_4x4x4_f32` (4x4 matrix multiply) and `dspm_mult_4x4x1_f32` +// (matrix * vector). These are S3-tuned hand-vectorized kernels that beat the +// scalar versions for both throughput and code-size. Detection is opt-in to +// keep the dependency optional: define SW_USE_ESP_DSP from your build system +// (or rely on the `idf_component.yml` example shown in the rlsw docs). +#if defined(ESP_PLATFORM) && defined(SW_USE_ESP_DSP) + #define SW_HAS_ESP_DSP + #include "dspm_mult.h" +#endif + #ifdef __cplusplus #define SW_CURLY_INIT(name) name #else @@ -1038,6 +1049,9 @@ typedef struct { SWmatrix currentMatrixMode; // Current matrix mode (e.g., sw_MODELVIEW, sw_PROJECTION) sw_matrix_t *currentMatrix; // Pointer to the currently used matrix according to the mode sw_matrix_t matMVP; // Model view projection matrix, calculated and used internally +#ifdef SW_HAS_ESP_DSP + float matMVP_rm[16]; // Row-major MVP, kept in sync for esp-dsp dspm_mult_4x4x1_f32 vertex transform +#endif bool isDirtyMVP; // Indicates if the MVP matrix should be rebuilt sw_handle_t boundFramebufferId; // Framebuffer currently bound @@ -1141,6 +1155,14 @@ static inline void sw_matrix_id(sw_matrix_t dst) static inline void sw_matrix_mul_rst(float *SW_RESTRICT dst, const float *SW_RESTRICT left, const float *SW_RESTRICT right) { +#ifdef SW_HAS_ESP_DSP + // dspm_mult_4x4x4_f32 treats its operands as row-major. rlsw stores matrices + // column-major, so passing them flat is equivalent to passing transposes: + // dspm_mult(L^T, R^T) computes (L^T)*(R^T) = (R*L)^T, written back into a + // flat array gives the same bit pattern as the column-major product (R*L) + // -- exactly the semantic the scalar fallback below has. + dspm_mult_4x4x4_f32(left, right, dst); +#else float l00 = left[0], l01 = left[1], l02 = left[2], l03 = left[3]; float l10 = left[4], l11 = left[5], l12 = left[6], l13 = left[7]; float l20 = left[8], l21 = left[9], l22 = left[10], l23 = left[11]; @@ -1165,6 +1187,7 @@ static inline void sw_matrix_mul_rst(float *SW_RESTRICT dst, const float *SW_RES dst[7] = l10*right[3] + l11*right[7] + l12*right[11] + l13*right[15]; dst[11] = l20*right[3] + l21*right[7] + l22*right[11] + l23*right[15]; dst[15] = l30*right[3] + l31*right[7] + l32*right[11] + l33*right[15]; +#endif } static inline void sw_matrix_mul(sw_matrix_t dst, const sw_matrix_t left, const sw_matrix_t right) @@ -3818,6 +3841,19 @@ static void sw_immediate_begin(SWdraw mode) RLSW.stackModelview[RLSW.stackModelviewCounter - 1], RLSW.stackProjection[RLSW.stackProjectionCounter - 1]); +#ifdef SW_HAS_ESP_DSP + // Pre-transpose to row-major so dspm_mult_4x4x1_f32(matMVP_rm, v, out) + // computes M*v directly in the per-vertex hot path. 16 scalar copies + // per MVP update vs. saving ~20 cycles per vertex transform. + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 4; j++) + { + RLSW.matMVP_rm[4*i + j] = RLSW.matMVP[4*j + i]; + } + } +#endif + RLSW.isDirtyMVP = false; } @@ -3869,11 +3905,17 @@ static void sw_immediate_push_vertex(const float position[4]) sw_vertex_t *vertex = &RLSW.primitive.buffer[RLSW.primitive.vertexCount++]; // Calculate clip coordinates +#ifdef SW_HAS_ESP_DSP + // dspm_mult_4x4x1_f32 declares its inputs non-const; rlsw treats them as + // read-only and the cast is safe (the kernel only loads from B). + dspm_mult_4x4x1_f32(RLSW.matMVP_rm, (float *)position, vertex->position); +#else const float *m = RLSW.matMVP; vertex->position[0] = m[0]*position[0] + m[4]*position[1] + m[8]*position[2] + m[12]*position[3]; vertex->position[1] = m[1]*position[0] + m[5]*position[1] + m[9]*position[2] + m[13]*position[3]; vertex->position[2] = m[2]*position[0] + m[6]*position[1] + m[10]*position[2] + m[14]*position[3]; vertex->position[3] = m[3]*position[0] + m[7]*position[1] + m[11]*position[2] + m[15]*position[3]; +#endif // Copy the attributes in the current vertex for (int i = 0; i < 4; i++) vertex->color[i] = RLSW.primitive.color[i];