Prepared support for acceleration: there is now a QueueCommands class that should

be used to feed the ring buffers with new commands. It takes care about proper
alignment (this shouldn't be necessary in the final version, anymore, though), and
locking.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17415 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-05-10 16:09:28 +00:00
parent fc88cd9396
commit 6c67d64cad
4 changed files with 144 additions and 55 deletions

View File

@ -77,8 +77,6 @@ extern void set_display_power_mode(uint32 mode);
// engine.cpp
extern void setup_ring_buffer(ring_buffer &ringBuffer, const char *name);
extern void write_to_ring(ring_buffer &ring, uint32 value);
extern void ring_command_complete(ring_buffer &ring);
// modes.cpp
extern status_t create_mode_list(void);

View File

@ -0,0 +1,43 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
*/
#ifndef COMMANDS_H
#define COMMANDS_H
#include "accelerant.h"
struct command {
uint32 opcode;
uint32 *Data() { return &opcode; }
virtual size_t Length() = 0;
};
class QueueCommands {
public:
QueueCommands(ring_buffer &ring);
~QueueCommands();
void Put(struct command &command);
void PutFlush();
void PutWaitFor(uint32 event);
void PutOverlayFlip(uint32 code, bool updateCoefficients);
private:
void _MakeSpace(uint32 size);
void _Write(uint32 data);
ring_buffer &fRingBuffer;
};
// commands
#endif // COMMANDS_H

View File

@ -9,6 +9,7 @@
#include "accelerant.h"
#include "accelerant_protos.h"
#include "commands.h"
#define TRACE_ENGINE
@ -23,37 +24,96 @@ extern "C" void _sPrintf(const char *format, ...);
static engine_token sEngineToken = {1, 0 /*B_2D_ACCELERATION*/, NULL};
/** The ring buffer must be locked when calling this function */
void
write_to_ring(ring_buffer &ring, uint32 value)
QueueCommands::QueueCommands(ring_buffer &ring)
:
fRingBuffer(ring)
{
uint32 *target = (uint32 *)(ring.base + ring.position);
*target = value;
ring.position = (ring.position + sizeof(uint32)) & (ring.size - 1);
acquire_lock(&fRingBuffer.lock);
}
/** The ring buffer must be locked when calling this function */
void
ring_command_complete(ring_buffer &ring)
QueueCommands::~QueueCommands()
{
if (ring.position & 0x07) {
if (fRingBuffer.position & 0x07) {
// make sure the command is properly aligned
write_to_ring(ring, COMMAND_NOOP);
_Write(COMMAND_NOOP);
}
write32(ring.register_base + RING_BUFFER_TAIL, ring.position);
write32(fRingBuffer.register_base + RING_BUFFER_TAIL, fRingBuffer.position);
// make sure memory is written back in case the ring buffer
// is in write combining mode
int32 test;
atomic_add(&test, 1);
// We must make sure memory is written back in case the ring buffer
// is in write combining mode - releasing the lock does this, as the
// buffer is flushed on a locked memory operation (which is what this
// benaphore does)
release_lock(&fRingBuffer.lock);
}
void
QueueCommands::Put(struct command &command)
{
uint32 count = command.Length();
uint32 *data = command.Data();
_MakeSpace(count);
for (uint32 i = 0; i < count; i++) {
_Write(data[i]);
}
}
void
QueueCommands::PutFlush()
{
_MakeSpace(2);
_Write(COMMAND_FLUSH);
_Write(COMMAND_NOOP);
}
void
QueueCommands::PutWaitFor(uint32 event)
{
_MakeSpace(2);
_Write(COMMAND_WAIT_FOR_EVENT | event);
_Write(COMMAND_NOOP);
}
void
QueueCommands::PutOverlayFlip(uint32 mode, bool updateCoefficients)
{
_MakeSpace(2);
_Write(COMMAND_OVERLAY_FLIP | mode);
_Write((uint32)gInfo->shared_info->physical_overlay_registers
| (updateCoefficients ? OVERLAY_UPDATE_COEFFICIENTS : 0));
}
void
QueueCommands::_MakeSpace(uint32 size)
{
// TODO: make sure there is enough room to write the command!
}
void
QueueCommands::_Write(uint32 data)
{
uint32 *target = (uint32 *)(fRingBuffer.base + fRingBuffer.position);
*target = data;
fRingBuffer.position = (fRingBuffer.position + sizeof(uint32)) & (fRingBuffer.size - 1);
}
// #pragma mark -
void
setup_ring_buffer(ring_buffer &ringBuffer, const char *name)
{
@ -75,7 +135,7 @@ setup_ring_buffer(ring_buffer &ringBuffer, const char *name)
}
// #pragma mark -
// #pragma mark - engine management
/** Return number of hardware engines */
@ -132,3 +192,6 @@ intel_sync_to_token(sync_token *syncToken)
return B_OK;
}
// #pragma mark - engine acceleration

View File

@ -12,6 +12,7 @@
#include "accelerant.h"
#include "accelerant_protos.h"
#include "commands.h"
#include <math.h>
#include <stdlib.h>
@ -225,19 +226,14 @@ update_overlay(bool updateCoefficients)
if (!gInfo->shared_info->overlay_active)
return;
ring_buffer &ringBuffer = gInfo->shared_info->secondary_ring_buffer;
write_to_ring(ringBuffer, COMMAND_FLUSH);
write_to_ring(ringBuffer, COMMAND_NOOP);
write_to_ring(ringBuffer, COMMAND_WAIT_FOR_EVENT | COMMAND_WAIT_FOR_OVERLAY_FLIP);
write_to_ring(ringBuffer, COMMAND_NOOP);
write_to_ring(ringBuffer, COMMAND_OVERLAY_FLIP | COMMAND_OVERLAY_CONTINUE);
write_to_ring(ringBuffer, (uint32)gInfo->shared_info->physical_overlay_registers
| (updateCoefficients ? OVERLAY_UPDATE_COEFFICIENTS : 0));
ring_command_complete(ringBuffer);
QueueCommands queue(gInfo->shared_info->secondary_ring_buffer);
queue.PutFlush();
queue.PutWaitFor(COMMAND_WAIT_FOR_OVERLAY_FLIP);
queue.PutOverlayFlip(COMMAND_OVERLAY_CONTINUE, updateCoefficients);
TRACE(("update overlay: UPDATE: %lx, TEST: %lx, STATUS: %lx, EXTENDED_STATUS: %lx\n",
read32(INTEL_OVERLAY_UPDATE), read32(INTEL_OVERLAY_TEST), read32(INTEL_OVERLAY_STATUS),
read32(INTEL_OVERLAY_EXTENDED_STATUS)));
// TRACE(("update overlay: UPDATE: %lx, TEST: %lx, STATUS: %lx, EXTENDED_STATUS: %lx\n",
// read32(INTEL_OVERLAY_UPDATE), read32(INTEL_OVERLAY_TEST), read32(INTEL_OVERLAY_STATUS),
// read32(INTEL_OVERLAY_EXTENDED_STATUS)));
}
@ -252,13 +248,9 @@ show_overlay(void)
gInfo->shared_info->overlay_active = true;
registers->overlay_enabled = true;
ring_buffer &ringBuffer = gInfo->shared_info->secondary_ring_buffer;
write_to_ring(ringBuffer, COMMAND_FLUSH);
write_to_ring(ringBuffer, COMMAND_NOOP);
write_to_ring(ringBuffer, COMMAND_OVERLAY_FLIP | COMMAND_OVERLAY_ON);
write_to_ring(ringBuffer, (uint32)gInfo->shared_info->physical_overlay_registers
| OVERLAY_UPDATE_COEFFICIENTS);
ring_command_complete(ringBuffer);
QueueCommands queue(gInfo->shared_info->secondary_ring_buffer);
queue.PutFlush();
queue.PutOverlayFlip(COMMAND_OVERLAY_ON, true);
}
@ -273,26 +265,19 @@ hide_overlay(void)
gInfo->shared_info->overlay_active = false;
registers->overlay_enabled = false;
ring_buffer &ringBuffer = gInfo->shared_info->secondary_ring_buffer;
QueueCommands queue(gInfo->shared_info->secondary_ring_buffer);
// flush pending commands
write_to_ring(ringBuffer, COMMAND_FLUSH);
write_to_ring(ringBuffer, COMMAND_NOOP);
write_to_ring(ringBuffer, COMMAND_WAIT_FOR_EVENT | COMMAND_WAIT_FOR_OVERLAY_FLIP);
write_to_ring(ringBuffer, COMMAND_NOOP);
queue.PutFlush();
queue.PutWaitFor(COMMAND_WAIT_FOR_OVERLAY_FLIP);
// clear overlay enabled bit
write_to_ring(ringBuffer, COMMAND_OVERLAY_FLIP | COMMAND_OVERLAY_CONTINUE);
write_to_ring(ringBuffer, (uint32)gInfo->shared_info->physical_overlay_registers);
write_to_ring(ringBuffer, COMMAND_WAIT_FOR_EVENT | COMMAND_WAIT_FOR_OVERLAY_FLIP);
write_to_ring(ringBuffer, COMMAND_NOOP);
queue.PutOverlayFlip(COMMAND_OVERLAY_CONTINUE, false);
queue.PutWaitFor(COMMAND_WAIT_FOR_OVERLAY_FLIP);
// turn off overlay engine
write_to_ring(ringBuffer, COMMAND_OVERLAY_FLIP | COMMAND_OVERLAY_OFF);
write_to_ring(ringBuffer, (uint32)gInfo->shared_info->physical_overlay_registers);
write_to_ring(ringBuffer, COMMAND_WAIT_FOR_EVENT | COMMAND_WAIT_FOR_OVERLAY_FLIP);
write_to_ring(ringBuffer, COMMAND_NOOP);
ring_command_complete(ringBuffer);
queue.PutOverlayFlip(COMMAND_OVERLAY_OFF, false);
queue.PutWaitFor(COMMAND_WAIT_FOR_OVERLAY_FLIP);
gInfo->current_overlay = NULL;
}