Your customers will be hella pissed at you if their favorite game suddenly doesn't work on their system after a driver update. So you need to test a representative sample of previously-working software across all hardware that the updated driver applies to.
That sounds like a nightmare, and a capital-intensive one because you need to keep machines up with all of these cards, both in continuous integration and for interactive debugging.
I can understand the impulse to keep the list of hardware that new driver versions support small.
For example, maybe you had a chip bug in the previous hardware generation which caused the system to hang after several days of stress testing. You found a software workaround for the bug, but every time you touch the code you need to re-verify the workaround, which takes days.
Of course, the downsides of forking the code are also very apparent...
I'm not defending them, but sometimes something is good enough and you have to move on.
It's possible that the AMD developers are from a Windows culture where they don't have to worry about this because Microsoft gives them a stable interface. Though even there, I find it questionable whether it's a win. Surely the occasional bug will surface that affects drivers for older hardware as well?
If driver version X worked but X+1 doesn't on your driver - don't update the driver. But when the driver is in the kernel trunk then that option isn't that simple.
The rule of three is not exclusive to the embedded world. It´s far better to have duplicate code around then to have to deal with poor generalizations that affect multiple independent modules, which in this case mean hardware support.
To put it in perspective, how many pieces of hardware would you require to re-test and validate if you decided to refactor bits of drivers that might share a common code path?
abstract class BaseDriver {
abstract commonThing()
}
abstract class BaseDriverV1 extends BaseDriver {
commonThing() {
console.log('This is the common method implementation for all V1 drivers')
}
abstract doThingOnlyV1Does()
}
class DriverV1_1 extends BaseDriverV1 {
doThingOnlyV1Does() {
console.log('This is how Driver V1.1 does the V1 thing')
}
}
This way you can use either an interface or an "abstract" definition that declares the base driver methods and the versioned driver methods, then provide version-dependent implementations where needed, or else share the common implementations by inheritance/extension.Maybe this turns into spaghetti at scale and it actually is easier to just copy-paste all of it, who knows.
How sure are you?
I mean, if the code path of a driver is touched, that triggers all verification and validation steps on all pieces of hardware that are required to ensure that the pieces of hardware affected by it will continue to work as expected.
Furthermore, how many bugs are introduced on a daily basis because people like you and me push "fairly clean patterns" that end up triggering all sorts of unexpected consequences? I know I did, and still do, my share.
Point being, maintain the code generator and not the generated code.
Without open sourcing their chips, it would probably be useless.
Even if you work for chip maker, that is what you usually get from hardware guys, so we are probably getting the same as AMD own driver programmers.
\s Welcome to wonderful world of driver development at majority of hardware houses \s
It's a good system. You shouldn't complain. And deleting code is easy since not everything depends on everything